1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2018 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Timm Friebe <thekid@thekid.de>                              |
16   |          George Schlossnagle <george@omniti.com>                     |
17   |          Andrei Zmievski <andrei@gravitonic.com>                     |
18   |          Marcus Boerger <helly@php.net>                              |
19   |          Johannes Schlueter <johannes@php.net>                       |
20   +----------------------------------------------------------------------+
21*/
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "php.h"
28#include "php_ini.h"
29#include "php_reflection.h"
30#include "ext/standard/info.h"
31
32#include "zend.h"
33#include "zend_API.h"
34#include "zend_exceptions.h"
35#include "zend_operators.h"
36#include "zend_constants.h"
37#include "zend_ini.h"
38#include "zend_interfaces.h"
39#include "zend_closures.h"
40#include "zend_generators.h"
41#include "zend_extensions.h"
42#include "zend_builtin_functions.h"
43#include "zend_smart_str.h"
44
45#define reflection_update_property(object, name, value) do { \
46		zval member; \
47		ZVAL_STR(&member, name); \
48		zend_std_write_property(object, &member, value, NULL); \
49		Z_TRY_DELREF_P(value); \
50		zval_ptr_dtor(&member); \
51	} while (0)
52
53#define reflection_update_property_name(object, value) \
54	reflection_update_property(object, ZSTR_KNOWN(ZEND_STR_NAME), value)
55
56#define reflection_update_property_class(object, value) \
57	reflection_update_property(object, ZSTR_KNOWN(ZEND_STR_CLASS), value)
58
59/* Class entry pointers */
60PHPAPI zend_class_entry *reflector_ptr;
61PHPAPI zend_class_entry *reflection_exception_ptr;
62PHPAPI zend_class_entry *reflection_ptr;
63PHPAPI zend_class_entry *reflection_function_abstract_ptr;
64PHPAPI zend_class_entry *reflection_function_ptr;
65PHPAPI zend_class_entry *reflection_generator_ptr;
66PHPAPI zend_class_entry *reflection_parameter_ptr;
67PHPAPI zend_class_entry *reflection_type_ptr;
68PHPAPI zend_class_entry *reflection_named_type_ptr;
69PHPAPI zend_class_entry *reflection_class_ptr;
70PHPAPI zend_class_entry *reflection_object_ptr;
71PHPAPI zend_class_entry *reflection_method_ptr;
72PHPAPI zend_class_entry *reflection_property_ptr;
73PHPAPI zend_class_entry *reflection_class_constant_ptr;
74PHPAPI zend_class_entry *reflection_extension_ptr;
75PHPAPI zend_class_entry *reflection_zend_extension_ptr;
76
77/* Exception throwing macro */
78#define _DO_THROW(msg)                                                                                      \
79	zend_throw_exception(reflection_exception_ptr, msg, 0);                                       \
80	return;                                                                                                 \
81
82#define RETURN_ON_EXCEPTION                                                                                 \
83	if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) {                            \
84		return;                                                                                             \
85	}
86
87#define GET_REFLECTION_OBJECT()	                                                                   			\
88	intern = Z_REFLECTION_P(getThis());                                                      				\
89	if (intern->ptr == NULL) {                                                            \
90		RETURN_ON_EXCEPTION                                                                                 \
91		zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object");        \
92		return;                                                                                             \
93	}                                                                                                       \
94
95#define GET_REFLECTION_OBJECT_PTR(target)                                                                   \
96	GET_REFLECTION_OBJECT()																					\
97	target = intern->ptr;                                                                                   \
98
99/* Class constants */
100#define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value)                                        \
101	zend_declare_class_constant_long(reflection_ ## class_name ## _ptr, const_name, sizeof(const_name)-1, (zend_long)value);
102
103/* {{{ Object structure */
104
105/* Struct for properties */
106typedef struct _property_reference {
107	zend_class_entry *ce;
108	zend_property_info prop;
109	zend_string *unmangled_name;
110} property_reference;
111
112/* Struct for parameters */
113typedef struct _parameter_reference {
114	uint32_t offset;
115	zend_bool required;
116	struct _zend_arg_info *arg_info;
117	zend_function *fptr;
118} parameter_reference;
119
120/* Struct for type hints */
121typedef struct _type_reference {
122	struct _zend_arg_info *arg_info;
123	zend_function *fptr;
124} type_reference;
125
126typedef enum {
127	REF_TYPE_OTHER,      /* Must be 0 */
128	REF_TYPE_FUNCTION,
129	REF_TYPE_GENERATOR,
130	REF_TYPE_PARAMETER,
131	REF_TYPE_TYPE,
132	REF_TYPE_PROPERTY,
133	REF_TYPE_CLASS_CONSTANT
134} reflection_type_t;
135
136/* Struct for reflection objects */
137typedef struct {
138	zval dummy; /* holder for the second property */
139	zval obj;
140	void *ptr;
141	zend_class_entry *ce;
142	reflection_type_t ref_type;
143	unsigned int ignore_visibility:1;
144	zend_object zo;
145} reflection_object;
146
147static inline reflection_object *reflection_object_from_obj(zend_object *obj) {
148	return (reflection_object*)((char*)(obj) - XtOffsetOf(reflection_object, zo));
149}
150
151#define Z_REFLECTION_P(zv)  reflection_object_from_obj(Z_OBJ_P((zv)))
152/* }}} */
153
154static zend_object_handlers reflection_object_handlers;
155
156static zval *_default_load_name(zval *object) /* {{{ */
157{
158	return zend_hash_find_ex_ind(Z_OBJPROP_P(object), ZSTR_KNOWN(ZEND_STR_NAME), 1);
159}
160/* }}} */
161
162static void _default_get_name(zval *object, zval *return_value) /* {{{ */
163{
164	zval *value;
165
166	if ((value = _default_load_name(object)) == NULL) {
167		RETURN_FALSE;
168	}
169	ZVAL_COPY(return_value, value);
170}
171/* }}} */
172
173static zend_function *_copy_function(zend_function *fptr) /* {{{ */
174{
175	if (fptr
176		&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
177	{
178		zend_function *copy_fptr;
179		copy_fptr = emalloc(sizeof(zend_function));
180		memcpy(copy_fptr, fptr, sizeof(zend_function));
181		copy_fptr->internal_function.function_name = zend_string_copy(fptr->internal_function.function_name);
182		return copy_fptr;
183	} else {
184		/* no copy needed */
185		return fptr;
186	}
187}
188/* }}} */
189
190static void _free_function(zend_function *fptr) /* {{{ */
191{
192	if (fptr
193		&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
194	{
195		zend_string_release_ex(fptr->internal_function.function_name, 0);
196		zend_free_trampoline(fptr);
197	}
198}
199/* }}} */
200
201static void reflection_free_objects_storage(zend_object *object) /* {{{ */
202{
203	reflection_object *intern = reflection_object_from_obj(object);
204	parameter_reference *reference;
205	property_reference *prop_reference;
206	type_reference *typ_reference;
207
208	if (intern->ptr) {
209		switch (intern->ref_type) {
210		case REF_TYPE_PARAMETER:
211			reference = (parameter_reference*)intern->ptr;
212			_free_function(reference->fptr);
213			efree(intern->ptr);
214			break;
215		case REF_TYPE_TYPE:
216			typ_reference = (type_reference*)intern->ptr;
217			_free_function(typ_reference->fptr);
218			efree(intern->ptr);
219			break;
220		case REF_TYPE_FUNCTION:
221			_free_function(intern->ptr);
222			break;
223		case REF_TYPE_PROPERTY:
224			prop_reference = (property_reference*)intern->ptr;
225			zend_string_release_ex(prop_reference->unmangled_name, 0);
226			efree(intern->ptr);
227			break;
228		case REF_TYPE_GENERATOR:
229		case REF_TYPE_CLASS_CONSTANT:
230		case REF_TYPE_OTHER:
231			break;
232		}
233	}
234	intern->ptr = NULL;
235	zval_ptr_dtor(&intern->obj);
236	zend_object_std_dtor(object);
237}
238/* }}} */
239
240static HashTable *reflection_get_gc(zval *obj, zval **gc_data, int *gc_data_count) /* {{{ */
241{
242	reflection_object *intern = Z_REFLECTION_P(obj);
243	*gc_data = &intern->obj;
244	*gc_data_count = 1;
245	return zend_std_get_properties(obj);
246}
247/* }}} */
248
249static zend_object *reflection_objects_new(zend_class_entry *class_type) /* {{{ */
250{
251	reflection_object *intern = zend_object_alloc(sizeof(reflection_object), class_type);
252
253	zend_object_std_init(&intern->zo, class_type);
254	object_properties_init(&intern->zo, class_type);
255	intern->zo.handlers = &reflection_object_handlers;
256	return &intern->zo;
257}
258/* }}} */
259
260static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
261{
262	object_init_ex(object, pce);
263	return object;
264}
265/* }}} */
266
267static void _const_string(smart_str *str, char *name, zval *value, char *indent);
268static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent);
269static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent);
270static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char* indent);
271static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent);
272static void _extension_string(smart_str *str, zend_module_entry *module, char *indent);
273static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent);
274
275/* {{{ _class_string */
276static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent)
277{
278	int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
279	zend_string *sub_indent = strpprintf(0, "%s    ", indent);
280
281	/* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
282	if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) {
283		smart_str_append_printf(str, "%s%s", indent, ZSTR_VAL(ce->info.user.doc_comment));
284		smart_str_appendc(str, '\n');
285	}
286
287	if (obj && Z_TYPE_P(obj) == IS_OBJECT) {
288		smart_str_append_printf(str, "%sObject of class [ ", indent);
289	} else {
290		char *kind = "Class";
291		if (ce->ce_flags & ZEND_ACC_INTERFACE) {
292			kind = "Interface";
293		} else if (ce->ce_flags & ZEND_ACC_TRAIT) {
294			kind = "Trait";
295		}
296		smart_str_append_printf(str, "%s%s [ ", indent, kind);
297	}
298	smart_str_append_printf(str, (ce->type == ZEND_USER_CLASS) ? "<user" : "<internal");
299	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module) {
300		smart_str_append_printf(str, ":%s", ce->info.internal.module->name);
301	}
302	smart_str_append_printf(str, "> ");
303	if (ce->get_iterator != NULL) {
304		smart_str_append_printf(str, "<iterateable> ");
305	}
306	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
307		smart_str_append_printf(str, "interface ");
308	} else if (ce->ce_flags & ZEND_ACC_TRAIT) {
309		smart_str_append_printf(str, "trait ");
310	} else {
311		if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
312			smart_str_append_printf(str, "abstract ");
313		}
314		if (ce->ce_flags & ZEND_ACC_FINAL) {
315			smart_str_append_printf(str, "final ");
316		}
317		smart_str_append_printf(str, "class ");
318	}
319	smart_str_append_printf(str, "%s", ZSTR_VAL(ce->name));
320	if (ce->parent) {
321		smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->parent->name));
322	}
323
324	if (ce->num_interfaces) {
325		uint32_t i;
326
327		if (ce->ce_flags & ZEND_ACC_INTERFACE) {
328			smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->interfaces[0]->name));
329		} else {
330			smart_str_append_printf(str, " implements %s", ZSTR_VAL(ce->interfaces[0]->name));
331		}
332		for (i = 1; i < ce->num_interfaces; ++i) {
333			smart_str_append_printf(str, ", %s", ZSTR_VAL(ce->interfaces[i]->name));
334		}
335	}
336	smart_str_append_printf(str, " ] {\n");
337
338	/* The information where a class is declared is only available for user classes */
339	if (ce->type == ZEND_USER_CLASS) {
340		smart_str_append_printf(str, "%s  @@ %s %d-%d\n", indent, ZSTR_VAL(ce->info.user.filename),
341						ce->info.user.line_start, ce->info.user.line_end);
342	}
343
344	/* Constants */
345	smart_str_append_printf(str, "\n");
346	count = zend_hash_num_elements(&ce->constants_table);
347	smart_str_append_printf(str, "%s  - Constants [%d] {\n", indent, count);
348	if (count > 0) {
349		zend_string *key;
350		zend_class_constant *c;
351
352		ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
353			_class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent));
354			if (UNEXPECTED(EG(exception))) {
355				return;
356			}
357		} ZEND_HASH_FOREACH_END();
358	}
359	smart_str_append_printf(str, "%s  }\n", indent);
360
361	/* Static properties */
362	/* counting static properties */
363	count = zend_hash_num_elements(&ce->properties_info);
364	if (count > 0) {
365		zend_property_info *prop;
366
367		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
368			if(prop->flags & ZEND_ACC_SHADOW) {
369				count_shadow_props++;
370			} else if (prop->flags & ZEND_ACC_STATIC) {
371				count_static_props++;
372			}
373		} ZEND_HASH_FOREACH_END();
374	}
375
376	/* static properties */
377	smart_str_append_printf(str, "\n%s  - Static properties [%d] {\n", indent, count_static_props);
378	if (count_static_props > 0) {
379		zend_property_info *prop;
380
381		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
382			if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) {
383				_property_string(str, prop, NULL, ZSTR_VAL(sub_indent));
384			}
385		} ZEND_HASH_FOREACH_END();
386	}
387	smart_str_append_printf(str, "%s  }\n", indent);
388
389	/* Static methods */
390	/* counting static methods */
391	count = zend_hash_num_elements(&ce->function_table);
392	if (count > 0) {
393		zend_function *mptr;
394
395		ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) {
396			if (mptr->common.fn_flags & ZEND_ACC_STATIC
397				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
398			{
399				count_static_funcs++;
400			}
401		} ZEND_HASH_FOREACH_END();
402	}
403
404	/* static methods */
405	smart_str_append_printf(str, "\n%s  - Static methods [%d] {", indent, count_static_funcs);
406	if (count_static_funcs > 0) {
407		zend_function *mptr;
408
409		ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) {
410			if (mptr->common.fn_flags & ZEND_ACC_STATIC
411				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
412			{
413				smart_str_append_printf(str, "\n");
414				_function_string(str, mptr, ce, ZSTR_VAL(sub_indent));
415			}
416		} ZEND_HASH_FOREACH_END();
417	} else {
418		smart_str_append_printf(str, "\n");
419	}
420	smart_str_append_printf(str, "%s  }\n", indent);
421
422	/* Default/Implicit properties */
423	count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
424	smart_str_append_printf(str, "\n%s  - Properties [%d] {\n", indent, count);
425	if (count > 0) {
426		zend_property_info *prop;
427
428		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
429			if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) {
430				_property_string(str, prop, NULL, ZSTR_VAL(sub_indent));
431			}
432		} ZEND_HASH_FOREACH_END();
433	}
434	smart_str_append_printf(str, "%s  }\n", indent);
435
436	if (obj && Z_TYPE_P(obj) == IS_OBJECT && Z_OBJ_HT_P(obj)->get_properties) {
437		HashTable    *properties = Z_OBJ_HT_P(obj)->get_properties(obj);
438		zend_string  *prop_name;
439		smart_str prop_str = {0};
440
441		count = 0;
442		if (properties && zend_hash_num_elements(properties)) {
443			ZEND_HASH_FOREACH_STR_KEY(properties, prop_name) {
444				if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */
445					if (!zend_hash_exists(&ce->properties_info, prop_name)) {
446						count++;
447						_property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent));
448					}
449				}
450			} ZEND_HASH_FOREACH_END();
451		}
452
453		smart_str_append_printf(str, "\n%s  - Dynamic properties [%d] {\n", indent, count);
454		smart_str_append_smart_str(str, &prop_str);
455		smart_str_append_printf(str, "%s  }\n", indent);
456		smart_str_free(&prop_str);
457	}
458
459	/* Non static methods */
460	count = zend_hash_num_elements(&ce->function_table) - count_static_funcs;
461	if (count > 0) {
462		zend_function *mptr;
463		zend_string *key;
464		smart_str method_str = {0};
465
466		count = 0;
467		ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, key, mptr) {
468			if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0
469				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
470			{
471				size_t len = ZSTR_LEN(mptr->common.function_name);
472
473				/* Do not display old-style inherited constructors */
474				if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0
475					|| mptr->common.scope == ce
476					|| !key
477					|| zend_binary_strcasecmp(ZSTR_VAL(key), ZSTR_LEN(key), ZSTR_VAL(mptr->common.function_name), len) == 0)
478				{
479					zend_function *closure;
480					/* see if this is a closure */
481					if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
482						&& memcmp(ZSTR_VAL(mptr->common.function_name), ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
483						&& (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL)
484					{
485						mptr = closure;
486					} else {
487						closure = NULL;
488					}
489					smart_str_appendc(&method_str, '\n');
490					_function_string(&method_str, mptr, ce, ZSTR_VAL(sub_indent));
491					count++;
492					_free_function(closure);
493				}
494			}
495		} ZEND_HASH_FOREACH_END();
496		smart_str_append_printf(str, "\n%s  - Methods [%d] {", indent, count);
497		smart_str_append_smart_str(str, &method_str);
498		if (!count) {
499			smart_str_append_printf(str, "\n");
500		}
501		smart_str_free(&method_str);
502	} else {
503		smart_str_append_printf(str, "\n%s  - Methods [0] {\n", indent);
504	}
505	smart_str_append_printf(str, "%s  }\n", indent);
506
507	smart_str_append_printf(str, "%s}\n", indent);
508	zend_string_release_ex(sub_indent, 0);
509}
510/* }}} */
511
512/* {{{ _const_string */
513static void _const_string(smart_str *str, char *name, zval *value, char *indent)
514{
515	char *type = zend_zval_type_name(value);
516
517	if (Z_TYPE_P(value) == IS_ARRAY) {
518		smart_str_append_printf(str, "%s    Constant [ %s %s ] { Array }\n",
519						indent, type, name);
520	} else if (Z_TYPE_P(value) == IS_STRING) {
521		smart_str_append_printf(str, "%s    Constant [ %s %s ] { %s }\n",
522						indent, type, name, Z_STRVAL_P(value));
523	} else {
524		zend_string *tmp_value_str;
525		zend_string *value_str = zval_get_tmp_string(value, &tmp_value_str);
526		smart_str_append_printf(str, "%s    Constant [ %s %s ] { %s }\n",
527						indent, type, name, ZSTR_VAL(value_str));
528		zend_tmp_string_release(tmp_value_str);
529	}
530}
531/* }}} */
532
533/* {{{ _class_const_string */
534static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char *indent)
535{
536	char *visibility = zend_visibility_string(Z_ACCESS_FLAGS(c->value));
537	char *type;
538
539	zval_update_constant_ex(&c->value, c->ce);
540	type = zend_zval_type_name(&c->value);
541
542	if (Z_TYPE(c->value) == IS_ARRAY) {
543		smart_str_append_printf(str, "%sConstant [ %s %s %s ] { Array }\n",
544						indent, visibility, type, name);
545	} else {
546		zend_string *tmp_value_str;
547		zend_string *value_str = zval_get_tmp_string(&c->value, &tmp_value_str);
548
549		smart_str_append_printf(str, "%sConstant [ %s %s %s ] { %s }\n",
550						indent, visibility, type, name, ZSTR_VAL(value_str));
551
552		zend_tmp_string_release(tmp_value_str);
553	}
554}
555/* }}} */
556
557/* {{{ _get_recv_opcode */
558static zend_op* _get_recv_op(zend_op_array *op_array, uint32_t offset)
559{
560	zend_op *op = op_array->opcodes;
561	zend_op *end = op + op_array->last;
562
563	++offset;
564	while (op < end) {
565		if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT
566		    || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == offset)
567		{
568			return op;
569		}
570		++op;
571	}
572	return NULL;
573}
574/* }}} */
575
576/* {{{ _parameter_string */
577static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_arg_info *arg_info, uint32_t offset, zend_bool required, char* indent)
578{
579	smart_str_append_printf(str, "Parameter #%d [ ", offset);
580	if (!required) {
581		smart_str_append_printf(str, "<optional> ");
582	} else {
583		smart_str_append_printf(str, "<required> ");
584	}
585	if (ZEND_TYPE_IS_CLASS(arg_info->type)) {
586		smart_str_append_printf(str, "%s ",
587			ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type)));
588		if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
589			smart_str_append_printf(str, "or NULL ");
590		}
591	} else if (ZEND_TYPE_IS_CODE(arg_info->type)) {
592		smart_str_append_printf(str, "%s ", zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)));
593		if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
594			smart_str_append_printf(str, "or NULL ");
595		}
596	}
597	if (arg_info->pass_by_reference) {
598		smart_str_appendc(str, '&');
599	}
600	if (arg_info->is_variadic) {
601		smart_str_appends(str, "...");
602	}
603	if (arg_info->name) {
604		smart_str_append_printf(str, "$%s",
605			(fptr->type == ZEND_INTERNAL_FUNCTION &&
606			 !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ?
607			((zend_internal_arg_info*)arg_info)->name :
608			ZSTR_VAL(arg_info->name));
609	} else {
610		smart_str_append_printf(str, "$param%d", offset);
611	}
612	if (fptr->type == ZEND_USER_FUNCTION && !required) {
613		zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset);
614		if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
615			zval zv;
616
617			smart_str_appends(str, " = ");
618			ZVAL_COPY(&zv, RT_CONSTANT(precv, precv->op2));
619			if (UNEXPECTED(zval_update_constant_ex(&zv, fptr->common.scope) == FAILURE)) {
620				zval_ptr_dtor(&zv);
621				return;
622			}
623			if (Z_TYPE(zv) == IS_TRUE) {
624				smart_str_appends(str, "true");
625			} else if (Z_TYPE(zv) == IS_FALSE) {
626				smart_str_appends(str, "false");
627			} else if (Z_TYPE(zv) == IS_NULL) {
628				smart_str_appends(str, "NULL");
629			} else if (Z_TYPE(zv) == IS_STRING) {
630				smart_str_appendc(str, '\'');
631				smart_str_appendl(str, Z_STRVAL(zv), MIN(Z_STRLEN(zv), 15));
632				if (Z_STRLEN(zv) > 15) {
633					smart_str_appends(str, "...");
634				}
635				smart_str_appendc(str, '\'');
636			} else if (Z_TYPE(zv) == IS_ARRAY) {
637				smart_str_appends(str, "Array");
638			} else {
639				zend_string *tmp_zv_str;
640				zend_string *zv_str = zval_get_tmp_string(&zv, &tmp_zv_str);
641				smart_str_append(str, zv_str);
642				zend_tmp_string_release(tmp_zv_str);
643			}
644			zval_ptr_dtor(&zv);
645		}
646	}
647	smart_str_appends(str, " ]");
648}
649/* }}} */
650
651/* {{{ _function_parameter_string */
652static void _function_parameter_string(smart_str *str, zend_function *fptr, char* indent)
653{
654	struct _zend_arg_info *arg_info = fptr->common.arg_info;
655	uint32_t i, num_args, num_required = fptr->common.required_num_args;
656
657	if (!arg_info) {
658		return;
659	}
660
661	num_args = fptr->common.num_args;
662	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
663		num_args++;
664	}
665	smart_str_appendc(str, '\n');
666	smart_str_append_printf(str, "%s- Parameters [%d] {\n", indent, num_args);
667	for (i = 0; i < num_args; i++) {
668		smart_str_append_printf(str, "%s  ", indent);
669		_parameter_string(str, fptr, arg_info, i, i < num_required, indent);
670		smart_str_appendc(str, '\n');
671		arg_info++;
672	}
673	smart_str_append_printf(str, "%s}\n", indent);
674}
675/* }}} */
676
677/* {{{ _function_closure_string */
678static void _function_closure_string(smart_str *str, zend_function *fptr, char* indent)
679{
680	uint32_t i, count;
681	zend_string *key;
682	HashTable *static_variables;
683
684	if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) {
685		return;
686	}
687
688	static_variables = fptr->op_array.static_variables;
689	count = zend_hash_num_elements(static_variables);
690
691	if (!count) {
692		return;
693	}
694
695	smart_str_append_printf(str, "\n");
696	smart_str_append_printf(str, "%s- Bound Variables [%d] {\n", indent, zend_hash_num_elements(static_variables));
697	i = 0;
698	ZEND_HASH_FOREACH_STR_KEY(static_variables, key) {
699		smart_str_append_printf(str, "%s    Variable #%d [ $%s ]\n", indent, i++, ZSTR_VAL(key));
700	} ZEND_HASH_FOREACH_END();
701	smart_str_append_printf(str, "%s}\n", indent);
702}
703/* }}} */
704
705/* {{{ _function_string */
706static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent)
707{
708	smart_str param_indent = {0};
709	zend_function *overwrites;
710	zend_string *lc_name;
711
712	/* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
713	 * What's "wrong" is that any whitespace before the doc comment start is
714	 * swallowed, leading to an unaligned comment.
715	 */
716	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
717		smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->op_array.doc_comment));
718	}
719
720	smart_str_appendl(str, indent, strlen(indent));
721	smart_str_append_printf(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ "));
722	smart_str_append_printf(str, (fptr->type == ZEND_USER_FUNCTION) ? "<user" : "<internal");
723	if (fptr->common.fn_flags & ZEND_ACC_DEPRECATED) {
724		smart_str_appends(str, ", deprecated");
725	}
726	if (fptr->type == ZEND_INTERNAL_FUNCTION && ((zend_internal_function*)fptr)->module) {
727		smart_str_append_printf(str, ":%s", ((zend_internal_function*)fptr)->module->name);
728	}
729
730	if (scope && fptr->common.scope) {
731		if (fptr->common.scope != scope) {
732			smart_str_append_printf(str, ", inherits %s", ZSTR_VAL(fptr->common.scope->name));
733		} else if (fptr->common.scope->parent) {
734			lc_name = zend_string_tolower(fptr->common.function_name);
735			if ((overwrites = zend_hash_find_ptr(&fptr->common.scope->parent->function_table, lc_name)) != NULL) {
736				if (fptr->common.scope != overwrites->common.scope) {
737					smart_str_append_printf(str, ", overwrites %s", ZSTR_VAL(overwrites->common.scope->name));
738				}
739			}
740			zend_string_release_ex(lc_name, 0);
741		}
742	}
743	if (fptr->common.prototype && fptr->common.prototype->common.scope) {
744		smart_str_append_printf(str, ", prototype %s", ZSTR_VAL(fptr->common.prototype->common.scope->name));
745	}
746	if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
747		smart_str_appends(str, ", ctor");
748	}
749	if (fptr->common.fn_flags & ZEND_ACC_DTOR) {
750		smart_str_appends(str, ", dtor");
751	}
752	smart_str_appends(str, "> ");
753
754	if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
755		smart_str_appends(str, "abstract ");
756	}
757	if (fptr->common.fn_flags & ZEND_ACC_FINAL) {
758		smart_str_appends(str, "final ");
759	}
760	if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
761		smart_str_appends(str, "static ");
762	}
763
764	if (fptr->common.scope) {
765		/* These are mutually exclusive */
766		switch (fptr->common.fn_flags & ZEND_ACC_PPP_MASK) {
767			case ZEND_ACC_PUBLIC:
768				smart_str_appends(str, "public ");
769				break;
770			case ZEND_ACC_PRIVATE:
771				smart_str_appends(str, "private ");
772				break;
773			case ZEND_ACC_PROTECTED:
774				smart_str_appends(str, "protected ");
775				break;
776			default:
777				smart_str_appends(str, "<visibility error> ");
778				break;
779		}
780		smart_str_appends(str, "method ");
781	} else {
782		smart_str_appends(str, "function ");
783	}
784
785	if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
786		smart_str_appendc(str, '&');
787	}
788	smart_str_append_printf(str, "%s ] {\n", ZSTR_VAL(fptr->common.function_name));
789	/* The information where a function is declared is only available for user classes */
790	if (fptr->type == ZEND_USER_FUNCTION) {
791		smart_str_append_printf(str, "%s  @@ %s %d - %d\n", indent,
792						ZSTR_VAL(fptr->op_array.filename),
793						fptr->op_array.line_start,
794						fptr->op_array.line_end);
795	}
796	smart_str_append_printf(&param_indent, "%s  ", indent);
797	smart_str_0(&param_indent);
798	if (fptr->common.fn_flags & ZEND_ACC_CLOSURE) {
799		_function_closure_string(str, fptr, ZSTR_VAL(param_indent.s));
800	}
801	_function_parameter_string(str, fptr, ZSTR_VAL(param_indent.s));
802	smart_str_free(&param_indent);
803	if (fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
804		smart_str_append_printf(str, "  %s- Return [ ", indent);
805		if (ZEND_TYPE_IS_CLASS(fptr->common.arg_info[-1].type)) {
806			smart_str_append_printf(str, "%s ",
807				ZSTR_VAL(ZEND_TYPE_NAME(fptr->common.arg_info[-1].type)));
808			if (ZEND_TYPE_ALLOW_NULL(fptr->common.arg_info[-1].type)) {
809				smart_str_appends(str, "or NULL ");
810			}
811		} else if (ZEND_TYPE_IS_CODE(fptr->common.arg_info[-1].type)) {
812			smart_str_append_printf(str, "%s ", zend_get_type_by_const(ZEND_TYPE_CODE(fptr->common.arg_info[-1].type)));
813			if (ZEND_TYPE_ALLOW_NULL(fptr->common.arg_info[-1].type)) {
814				smart_str_appends(str, "or NULL ");
815			}
816		}
817		smart_str_appends(str, "]\n");
818	}
819	smart_str_append_printf(str, "%s}\n", indent);
820}
821/* }}} */
822
823/* {{{ _property_string */
824static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent)
825{
826	smart_str_append_printf(str, "%sProperty [ ", indent);
827	if (!prop) {
828		smart_str_append_printf(str, "<dynamic> public $%s", prop_name);
829	} else {
830		if (!(prop->flags & ZEND_ACC_STATIC)) {
831			if (prop->flags & ZEND_ACC_IMPLICIT_PUBLIC) {
832				smart_str_appends(str, "<implicit> ");
833			} else {
834				smart_str_appends(str, "<default> ");
835			}
836		}
837
838		/* These are mutually exclusive */
839		switch (prop->flags & ZEND_ACC_PPP_MASK) {
840			case ZEND_ACC_PUBLIC:
841				smart_str_appends(str, "public ");
842				break;
843			case ZEND_ACC_PRIVATE:
844				smart_str_appends(str, "private ");
845				break;
846			case ZEND_ACC_PROTECTED:
847				smart_str_appends(str, "protected ");
848				break;
849		}
850		if (prop->flags & ZEND_ACC_STATIC) {
851			smart_str_appends(str, "static ");
852		}
853		if (!prop_name) {
854			const char *class_name;
855			zend_unmangle_property_name(prop->name, &class_name, &prop_name);
856		}
857		smart_str_append_printf(str, "$%s", prop_name);
858	}
859
860	smart_str_appends(str, " ]\n");
861}
862/* }}} */
863
864static int _extension_ini_string(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
865{
866	zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el);
867	smart_str *str = va_arg(args, smart_str *);
868	char *indent = va_arg(args, char *);
869	int number = va_arg(args, int);
870	char *comma = "";
871
872	if (number == ini_entry->module_number) {
873		smart_str_append_printf(str, "    %sEntry [ %s <", indent, ZSTR_VAL(ini_entry->name));
874		if (ini_entry->modifiable == ZEND_INI_ALL) {
875			smart_str_appends(str, "ALL");
876		} else {
877			if (ini_entry->modifiable & ZEND_INI_USER) {
878				smart_str_appends(str, "USER");
879				comma = ",";
880			}
881			if (ini_entry->modifiable & ZEND_INI_PERDIR) {
882				smart_str_append_printf(str, "%sPERDIR", comma);
883				comma = ",";
884			}
885			if (ini_entry->modifiable & ZEND_INI_SYSTEM) {
886				smart_str_append_printf(str, "%sSYSTEM", comma);
887			}
888		}
889
890		smart_str_appends(str, "> ]\n");
891		smart_str_append_printf(str, "    %s  Current = '%s'\n", indent, ini_entry->value ? ZSTR_VAL(ini_entry->value) : "");
892		if (ini_entry->modified) {
893			smart_str_append_printf(str, "    %s  Default = '%s'\n", indent, ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : "");
894		}
895		smart_str_append_printf(str, "    %s}\n", indent);
896	}
897	return ZEND_HASH_APPLY_KEEP;
898}
899/* }}} */
900
901static int _extension_class_string(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
902{
903	zend_class_entry *ce = (zend_class_entry*)Z_PTR_P(el);
904	smart_str *str = va_arg(args, smart_str *);
905	char *indent = va_arg(args, char *);
906	struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
907	int *num_classes = va_arg(args, int*);
908
909	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
910		/* dump class if it is not an alias */
911		if (!zend_binary_strcasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(hash_key->key), ZSTR_LEN(hash_key->key))) {
912			smart_str_append_printf(str, "\n");
913			_class_string(str, ce, NULL, indent);
914			(*num_classes)++;
915		}
916	}
917	return ZEND_HASH_APPLY_KEEP;
918}
919/* }}} */
920
921static int _extension_const_string(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
922{
923	zend_constant *constant = (zend_constant*)Z_PTR_P(el);
924	smart_str *str = va_arg(args, smart_str *);
925	char *indent = va_arg(args, char *);
926	struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
927	int *num_classes = va_arg(args, int*);
928
929	if (ZEND_CONSTANT_MODULE_NUMBER(constant)  == module->module_number) {
930		_const_string(str, ZSTR_VAL(constant->name), &constant->value, indent);
931		(*num_classes)++;
932	}
933	return ZEND_HASH_APPLY_KEEP;
934}
935/* }}} */
936
937static void _extension_string(smart_str *str, zend_module_entry *module, char *indent) /* {{{ */
938{
939	smart_str_append_printf(str, "%sExtension [ ", indent);
940	if (module->type == MODULE_PERSISTENT) {
941		smart_str_appends(str, "<persistent>");
942	}
943	if (module->type == MODULE_TEMPORARY) {
944		smart_str_appends(str, "<temporary>" );
945	}
946	smart_str_append_printf(str, " extension #%d %s version %s ] {\n",
947					module->module_number, module->name,
948					(module->version == NO_VERSION_YET) ? "<no_version>" : module->version);
949
950	if (module->deps) {
951		const zend_module_dep* dep = module->deps;
952
953		smart_str_appends(str, "\n  - Dependencies {\n");
954
955		while(dep->name) {
956			smart_str_append_printf(str, "%s    Dependency [ %s (", indent, dep->name);
957
958			switch(dep->type) {
959			case MODULE_DEP_REQUIRED:
960				smart_str_appends(str, "Required");
961				break;
962			case MODULE_DEP_CONFLICTS:
963				smart_str_appends(str, "Conflicts");
964				break;
965			case MODULE_DEP_OPTIONAL:
966				smart_str_appends(str, "Optional");
967				break;
968			default:
969				smart_str_appends(str, "Error"); /* shouldn't happen */
970				break;
971			}
972
973			if (dep->rel) {
974				smart_str_append_printf(str, " %s", dep->rel);
975			}
976			if (dep->version) {
977				smart_str_append_printf(str, " %s", dep->version);
978			}
979			smart_str_appends(str, ") ]\n");
980			dep++;
981		}
982		smart_str_append_printf(str, "%s  }\n", indent);
983	}
984
985	{
986		smart_str str_ini = {0};
987		zend_hash_apply_with_arguments(EG(ini_directives), (apply_func_args_t) _extension_ini_string, 3, &str_ini, indent, module->module_number);
988		if (smart_str_get_len(&str_ini) > 0) {
989			smart_str_append_printf(str, "\n  - INI {\n");
990			smart_str_append_smart_str(str, &str_ini);
991			smart_str_append_printf(str, "%s  }\n", indent);
992		}
993		smart_str_free(&str_ini);
994	}
995
996	{
997		smart_str str_constants = {0};
998		int num_constants = 0;
999
1000		zend_hash_apply_with_arguments(EG(zend_constants), (apply_func_args_t) _extension_const_string, 4, &str_constants, indent, module, &num_constants);
1001		if (num_constants) {
1002			smart_str_append_printf(str, "\n  - Constants [%d] {\n", num_constants);
1003			smart_str_append_smart_str(str, &str_constants);
1004			smart_str_append_printf(str, "%s  }\n", indent);
1005		}
1006		smart_str_free(&str_constants);
1007	}
1008
1009	{
1010		zend_function *fptr;
1011		int first = 1;
1012
1013		ZEND_HASH_FOREACH_PTR(CG(function_table), fptr) {
1014			if (fptr->common.type==ZEND_INTERNAL_FUNCTION
1015				&& fptr->internal_function.module == module) {
1016				if (first) {
1017					smart_str_append_printf(str, "\n  - Functions {\n");
1018					first = 0;
1019				}
1020				_function_string(str, fptr, NULL, "    ");
1021			}
1022		} ZEND_HASH_FOREACH_END();
1023		if (!first) {
1024			smart_str_append_printf(str, "%s  }\n", indent);
1025		}
1026	}
1027
1028	{
1029		zend_string *sub_indent = strpprintf(0, "%s    ", indent);
1030		smart_str str_classes = {0};
1031		int num_classes = 0;
1032
1033		zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) _extension_class_string, 4, &str_classes, ZSTR_VAL(sub_indent), module, &num_classes);
1034		if (num_classes) {
1035			smart_str_append_printf(str, "\n  - Classes [%d] {", num_classes);
1036			smart_str_append_smart_str(str, &str_classes);
1037			smart_str_append_printf(str, "%s  }\n", indent);
1038		}
1039		smart_str_free(&str_classes);
1040		zend_string_release_ex(sub_indent, 0);
1041	}
1042
1043	smart_str_append_printf(str, "%s}\n", indent);
1044}
1045/* }}} */
1046
1047static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent) /* {{{ */
1048{
1049	smart_str_append_printf(str, "%sZend Extension [ %s ", indent, extension->name);
1050
1051	if (extension->version) {
1052		smart_str_append_printf(str, "%s ", extension->version);
1053	}
1054	if (extension->copyright) {
1055		smart_str_append_printf(str, "%s ", extension->copyright);
1056	}
1057	if (extension->author) {
1058		smart_str_append_printf(str, "by %s ", extension->author);
1059	}
1060	if (extension->URL) {
1061		smart_str_append_printf(str, "<%s> ", extension->URL);
1062	}
1063
1064	smart_str_appends(str, "]\n");
1065}
1066/* }}} */
1067
1068/* {{{ _function_check_flag */
1069static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
1070{
1071	reflection_object *intern;
1072	zend_function *mptr;
1073
1074	if (zend_parse_parameters_none() == FAILURE) {
1075		return;
1076	}
1077	GET_REFLECTION_OBJECT_PTR(mptr);
1078	RETURN_BOOL(mptr->common.fn_flags & mask);
1079}
1080/* }}} */
1081
1082/* {{{ zend_reflection_class_factory */
1083PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object)
1084{
1085	reflection_object *intern;
1086	zval name;
1087
1088	ZVAL_STR_COPY(&name, ce->name);
1089	reflection_instantiate(reflection_class_ptr, object);
1090	intern = Z_REFLECTION_P(object);
1091	intern->ptr = ce;
1092	intern->ref_type = REF_TYPE_OTHER;
1093	intern->ce = ce;
1094	reflection_update_property_name(object, &name);
1095}
1096/* }}} */
1097
1098/* {{{ reflection_extension_factory */
1099static void reflection_extension_factory(zval *object, const char *name_str)
1100{
1101	reflection_object *intern;
1102	zval name;
1103	size_t name_len = strlen(name_str);
1104	zend_string *lcname;
1105	struct _zend_module_entry *module;
1106
1107	lcname = zend_string_alloc(name_len, 0);
1108	zend_str_tolower_copy(ZSTR_VAL(lcname), name_str, name_len);
1109	module = zend_hash_find_ptr(&module_registry, lcname);
1110	zend_string_efree(lcname);
1111	if (!module) {
1112		return;
1113	}
1114
1115	reflection_instantiate(reflection_extension_ptr, object);
1116	intern = Z_REFLECTION_P(object);
1117	ZVAL_STRINGL(&name, module->name, name_len);
1118	intern->ptr = module;
1119	intern->ref_type = REF_TYPE_OTHER;
1120	intern->ce = NULL;
1121	reflection_update_property_name(object, &name);
1122}
1123/* }}} */
1124
1125/* {{{ reflection_parameter_factory */
1126static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, uint32_t offset, zend_bool required, zval *object)
1127{
1128	reflection_object *intern;
1129	parameter_reference *reference;
1130	zval name;
1131
1132	if (arg_info->name) {
1133		if (fptr->type == ZEND_INTERNAL_FUNCTION &&
1134		    !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
1135			ZVAL_STRING(&name, ((zend_internal_arg_info*)arg_info)->name);
1136		} else {
1137			ZVAL_STR_COPY(&name, arg_info->name);
1138		}
1139	} else {
1140		ZVAL_NULL(&name);
1141	}
1142	reflection_instantiate(reflection_parameter_ptr, object);
1143	intern = Z_REFLECTION_P(object);
1144	reference = (parameter_reference*) emalloc(sizeof(parameter_reference));
1145	reference->arg_info = arg_info;
1146	reference->offset = offset;
1147	reference->required = required;
1148	reference->fptr = fptr;
1149	intern->ptr = reference;
1150	intern->ref_type = REF_TYPE_PARAMETER;
1151	intern->ce = fptr->common.scope;
1152	if (closure_object) {
1153		Z_ADDREF_P(closure_object);
1154		ZVAL_COPY_VALUE(&intern->obj, closure_object);
1155	}
1156	reflection_update_property_name(object, &name);
1157}
1158/* }}} */
1159
1160/* {{{ reflection_type_factory */
1161static void reflection_type_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, zval *object)
1162{
1163	reflection_object *intern;
1164	type_reference *reference;
1165
1166	reflection_instantiate(reflection_named_type_ptr, object);
1167	intern = Z_REFLECTION_P(object);
1168	reference = (type_reference*) emalloc(sizeof(type_reference));
1169	reference->arg_info = arg_info;
1170	reference->fptr = fptr;
1171	intern->ptr = reference;
1172	intern->ref_type = REF_TYPE_TYPE;
1173	intern->ce = fptr->common.scope;
1174	if (closure_object) {
1175		Z_ADDREF_P(closure_object);
1176		ZVAL_COPY_VALUE(&intern->obj, closure_object);
1177	}
1178}
1179/* }}} */
1180
1181/* {{{ reflection_function_factory */
1182static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object)
1183{
1184	reflection_object *intern;
1185	zval name;
1186
1187	ZVAL_STR_COPY(&name, function->common.function_name);
1188
1189	reflection_instantiate(reflection_function_ptr, object);
1190	intern = Z_REFLECTION_P(object);
1191	intern->ptr = function;
1192	intern->ref_type = REF_TYPE_FUNCTION;
1193	intern->ce = NULL;
1194	if (closure_object) {
1195		Z_ADDREF_P(closure_object);
1196		ZVAL_COPY_VALUE(&intern->obj, closure_object);
1197	}
1198	reflection_update_property_name(object, &name);
1199}
1200/* }}} */
1201
1202/* {{{ reflection_method_factory */
1203static void reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object)
1204{
1205	reflection_object *intern;
1206	zval name;
1207	zval classname;
1208
1209	ZVAL_STR_COPY(&name, (method->common.scope && method->common.scope->trait_aliases)?
1210			zend_resolve_method_name(ce, method) : method->common.function_name);
1211	ZVAL_STR_COPY(&classname, method->common.scope->name);
1212	reflection_instantiate(reflection_method_ptr, object);
1213	intern = Z_REFLECTION_P(object);
1214	intern->ptr = method;
1215	intern->ref_type = REF_TYPE_FUNCTION;
1216	intern->ce = ce;
1217	if (closure_object) {
1218		Z_ADDREF_P(closure_object);
1219		ZVAL_COPY_VALUE(&intern->obj, closure_object);
1220	}
1221	reflection_update_property_name(object, &name);
1222	reflection_update_property_class(object, &classname);
1223}
1224/* }}} */
1225
1226/* {{{ reflection_property_factory */
1227static void reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object)
1228{
1229	reflection_object *intern;
1230	zval propname;
1231	zval classname;
1232	property_reference *reference;
1233
1234	if (!(prop->flags & ZEND_ACC_PRIVATE)) {
1235		/* we have to search the class hierarchy for this (implicit) public or protected property */
1236		zend_class_entry *tmp_ce = ce, *store_ce = ce;
1237		zend_property_info *tmp_info = NULL;
1238
1239		while (tmp_ce && (tmp_info = zend_hash_find_ptr(&tmp_ce->properties_info, name)) == NULL) {
1240			ce = tmp_ce;
1241			tmp_ce = tmp_ce->parent;
1242		}
1243
1244		if (tmp_info && !(tmp_info->flags & ZEND_ACC_SHADOW)) { /* found something and it's not a parent's private */
1245			prop = tmp_info;
1246		} else { /* not found, use initial value */
1247			ce = store_ce;
1248		}
1249	}
1250
1251	ZVAL_STR_COPY(&propname, name);
1252	ZVAL_STR_COPY(&classname, prop->ce->name);
1253
1254	reflection_instantiate(reflection_property_ptr, object);
1255	intern = Z_REFLECTION_P(object);
1256	reference = (property_reference*) emalloc(sizeof(property_reference));
1257	reference->ce = ce;
1258	reference->prop = *prop;
1259	reference->unmangled_name = zend_string_copy(name);
1260	intern->ptr = reference;
1261	intern->ref_type = REF_TYPE_PROPERTY;
1262	intern->ce = ce;
1263	intern->ignore_visibility = 0;
1264	reflection_update_property_name(object, &propname);
1265	reflection_update_property_class(object, &classname);
1266}
1267/* }}} */
1268
1269static void reflection_property_factory_str(zend_class_entry *ce, const char *name_str, size_t name_len, zend_property_info *prop, zval *object)
1270{
1271	zend_string *name = zend_string_init(name_str, name_len, 0);
1272	reflection_property_factory(ce, name, prop, object);
1273	zend_string_release(name);
1274}
1275
1276/* {{{ reflection_class_constant_factory */
1277static void reflection_class_constant_factory(zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object)
1278{
1279	reflection_object *intern;
1280	zval name;
1281	zval classname;
1282
1283	ZVAL_STR_COPY(&name, name_str);
1284	ZVAL_STR_COPY(&classname, ce->name);
1285
1286	reflection_instantiate(reflection_class_constant_ptr, object);
1287	intern = Z_REFLECTION_P(object);
1288	intern->ptr = constant;
1289	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
1290	intern->ce = constant->ce;
1291	intern->ignore_visibility = 0;
1292	reflection_update_property_name(object, &name);
1293	reflection_update_property_class(object, &classname);
1294}
1295/* }}} */
1296
1297/* {{{ _reflection_export */
1298static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc)
1299{
1300	zval reflector;
1301	zval *argument_ptr, *argument2_ptr;
1302	zval retval, params[2];
1303	int result;
1304	int return_output = 0;
1305	zend_fcall_info fci;
1306	zend_fcall_info_cache fcc;
1307
1308	if (ctor_argc == 1) {
1309		if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &argument_ptr, &return_output) == FAILURE) {
1310			return;
1311		}
1312		ZVAL_COPY_VALUE(&params[0], argument_ptr);
1313		ZVAL_NULL(&params[1]);
1314	} else {
1315		if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|b", &argument_ptr, &argument2_ptr, &return_output) == FAILURE) {
1316			return;
1317		}
1318		ZVAL_COPY_VALUE(&params[0], argument_ptr);
1319		ZVAL_COPY_VALUE(&params[1], argument2_ptr);
1320	}
1321
1322	/* Create object */
1323	if (object_and_properties_init(&reflector, ce_ptr, NULL) == FAILURE) {
1324		_DO_THROW("Could not create reflector");
1325	}
1326
1327	/* Call __construct() */
1328
1329	fci.size = sizeof(fci);
1330	ZVAL_UNDEF(&fci.function_name);
1331	fci.object = Z_OBJ(reflector);
1332	fci.retval = &retval;
1333	fci.param_count = ctor_argc;
1334	fci.params = params;
1335	fci.no_separation = 1;
1336
1337	fcc.function_handler = ce_ptr->constructor;
1338	fcc.called_scope = Z_OBJCE(reflector);
1339	fcc.object = Z_OBJ(reflector);
1340
1341	result = zend_call_function(&fci, &fcc);
1342
1343	zval_ptr_dtor(&retval);
1344
1345	if (EG(exception)) {
1346		zval_ptr_dtor(&reflector);
1347		return;
1348	}
1349	if (result == FAILURE) {
1350		zval_ptr_dtor(&reflector);
1351		_DO_THROW("Could not create reflector");
1352	}
1353
1354	/* Call static reflection::export */
1355	ZVAL_COPY_VALUE(&params[0], &reflector);
1356	ZVAL_BOOL(&params[1], return_output);
1357
1358	ZVAL_STRINGL(&fci.function_name, "reflection::export", sizeof("reflection::export") - 1);
1359	fci.object = NULL;
1360	fci.retval = &retval;
1361	fci.param_count = 2;
1362	fci.params = params;
1363	fci.no_separation = 1;
1364
1365	result = zend_call_function(&fci, NULL);
1366
1367	zval_ptr_dtor(&fci.function_name);
1368
1369	if (result == FAILURE && EG(exception) == NULL) {
1370		zval_ptr_dtor(&reflector);
1371		zval_ptr_dtor(&retval);
1372		_DO_THROW("Could not execute reflection::export()");
1373	}
1374
1375	if (return_output) {
1376		ZVAL_COPY_VALUE(return_value, &retval);
1377	} else {
1378		zval_ptr_dtor(&retval);
1379	}
1380
1381	/* Destruct reflector which is no longer needed */
1382	zval_ptr_dtor(&reflector);
1383}
1384/* }}} */
1385
1386/* {{{ _reflection_param_get_default_param */
1387static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTION_PARAMETERS)
1388{
1389	reflection_object *intern;
1390	parameter_reference *param;
1391
1392	intern = Z_REFLECTION_P(getThis());
1393	if (intern->ptr == NULL) {
1394		if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) {
1395			return NULL;
1396		}
1397		zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object");
1398		return NULL;
1399	}
1400
1401	param = intern->ptr;
1402	if (param->fptr->type != ZEND_USER_FUNCTION) {
1403		zend_throw_exception_ex(reflection_exception_ptr, 0, "Cannot determine default value for internal functions");
1404		return NULL;
1405	}
1406
1407	return param;
1408}
1409/* }}} */
1410
1411/* {{{ _reflection_param_get_default_precv */
1412static zend_op *_reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAMETERS, parameter_reference *param)
1413{
1414	zend_op *precv;
1415
1416	if (param == NULL) {
1417		return NULL;
1418	}
1419
1420	precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
1421	if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
1422		zend_throw_exception_ex(reflection_exception_ptr, 0, "Internal error: Failed to retrieve the default value");
1423		return NULL;
1424	}
1425
1426	return precv;
1427}
1428/* }}} */
1429
1430/* {{{ Preventing __clone from being called */
1431ZEND_METHOD(reflection, __clone)
1432{
1433	/* Should never be executable */
1434	_DO_THROW("Cannot clone object using __clone()");
1435}
1436/* }}} */
1437
1438/* {{{ proto public static mixed Reflection::export(Reflector r [, bool return])
1439   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
1440ZEND_METHOD(reflection, export)
1441{
1442	zval *object, fname, retval;
1443	int result;
1444	zend_bool return_output = 0;
1445
1446	ZEND_PARSE_PARAMETERS_START(1, 2)
1447		Z_PARAM_OBJECT_OF_CLASS(object, reflector_ptr)
1448		Z_PARAM_OPTIONAL
1449		Z_PARAM_BOOL(return_output)
1450	ZEND_PARSE_PARAMETERS_END();
1451
1452	/* Invoke the __toString() method */
1453	ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1);
1454	result= call_user_function(NULL, object, &fname, &retval, 0, NULL);
1455	zval_ptr_dtor_str(&fname);
1456
1457	if (result == FAILURE) {
1458		_DO_THROW("Invocation of method __toString() failed");
1459		/* Returns from this function */
1460	}
1461
1462	if (Z_TYPE(retval) == IS_UNDEF) {
1463		php_error_docref(NULL, E_WARNING, "%s::__toString() did not return anything", ZSTR_VAL(Z_OBJCE_P(object)->name));
1464		RETURN_FALSE;
1465	}
1466
1467	if (return_output) {
1468		ZVAL_COPY_VALUE(return_value, &retval);
1469	} else {
1470		/* No need for _r variant, return of __toString should always be a string */
1471		zend_print_zval(&retval, 0);
1472		zend_printf("\n");
1473		zval_ptr_dtor(&retval);
1474	}
1475}
1476/* }}} */
1477
1478/* {{{ proto public static array Reflection::getModifierNames(int modifiers)
1479   Returns an array of modifier names */
1480ZEND_METHOD(reflection, getModifierNames)
1481{
1482	zend_long modifiers;
1483
1484	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &modifiers) == FAILURE) {
1485		return;
1486	}
1487
1488	array_init(return_value);
1489
1490	if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1491		add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1);
1492	}
1493	if (modifiers & ZEND_ACC_FINAL) {
1494		add_next_index_stringl(return_value, "final", sizeof("final")-1);
1495	}
1496	if (modifiers & ZEND_ACC_IMPLICIT_PUBLIC) {
1497		add_next_index_stringl(return_value, "public", sizeof("public")-1);
1498	}
1499
1500	/* These are mutually exclusive */
1501	switch (modifiers & ZEND_ACC_PPP_MASK) {
1502		case ZEND_ACC_PUBLIC:
1503			add_next_index_stringl(return_value, "public", sizeof("public")-1);
1504			break;
1505		case ZEND_ACC_PRIVATE:
1506			add_next_index_stringl(return_value, "private", sizeof("private")-1);
1507			break;
1508		case ZEND_ACC_PROTECTED:
1509			add_next_index_stringl(return_value, "protected", sizeof("protected")-1);
1510			break;
1511	}
1512
1513	if (modifiers & ZEND_ACC_STATIC) {
1514		add_next_index_stringl(return_value, "static", sizeof("static")-1);
1515	}
1516}
1517/* }}} */
1518
1519/* {{{ proto public static mixed ReflectionFunction::export(string name [, bool return])
1520   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
1521ZEND_METHOD(reflection_function, export)
1522{
1523	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_function_ptr, 1);
1524}
1525/* }}} */
1526
1527/* {{{ proto public void ReflectionFunction::__construct(string name)
1528   Constructor. Throws an Exception in case the given function does not exist */
1529ZEND_METHOD(reflection_function, __construct)
1530{
1531	zval name;
1532	zval *object;
1533	zval *closure = NULL;
1534	reflection_object *intern;
1535	zend_function *fptr;
1536	zend_string *fname, *lcname;
1537
1538	object = getThis();
1539	intern = Z_REFLECTION_P(object);
1540
1541	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == SUCCESS) {
1542		fptr = (zend_function*)zend_get_closure_method_def(closure);
1543		Z_ADDREF_P(closure);
1544	} else {
1545		ALLOCA_FLAG(use_heap)
1546
1547		if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "S", &fname) == FAILURE) {
1548			return;
1549		}
1550
1551		if (UNEXPECTED(ZSTR_VAL(fname)[0] == '\\')) {
1552			/* Ignore leading "\" */
1553			ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(fname) - 1, use_heap);
1554			zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(fname) + 1, ZSTR_LEN(fname) - 1);
1555			fptr = zend_fetch_function(lcname);
1556			ZSTR_ALLOCA_FREE(lcname, use_heap);
1557		} else {
1558			lcname = zend_string_tolower(fname);
1559			fptr = zend_fetch_function(lcname);
1560			zend_string_release(lcname);
1561		}
1562
1563		if (fptr == NULL) {
1564			zend_throw_exception_ex(reflection_exception_ptr, 0,
1565				"Function %s() does not exist", ZSTR_VAL(fname));
1566			return;
1567		}
1568	}
1569
1570	ZVAL_STR_COPY(&name, fptr->common.function_name);
1571	reflection_update_property_name(object, &name);
1572	intern->ptr = fptr;
1573	intern->ref_type = REF_TYPE_FUNCTION;
1574	if (closure) {
1575		ZVAL_COPY_VALUE(&intern->obj, closure);
1576	} else {
1577		ZVAL_UNDEF(&intern->obj);
1578	}
1579	intern->ce = NULL;
1580}
1581/* }}} */
1582
1583/* {{{ proto public string ReflectionFunction::__toString()
1584   Returns a string representation */
1585ZEND_METHOD(reflection_function, __toString)
1586{
1587	reflection_object *intern;
1588	zend_function *fptr;
1589	smart_str str = {0};
1590
1591	if (zend_parse_parameters_none() == FAILURE) {
1592		return;
1593	}
1594	GET_REFLECTION_OBJECT_PTR(fptr);
1595	_function_string(&str, fptr, intern->ce, "");
1596	RETURN_STR(smart_str_extract(&str));
1597}
1598/* }}} */
1599
1600/* {{{ proto public string ReflectionFunction::getName()
1601   Returns this function's name */
1602ZEND_METHOD(reflection_function, getName)
1603{
1604	if (zend_parse_parameters_none() == FAILURE) {
1605		return;
1606	}
1607	_default_get_name(getThis(), return_value);
1608}
1609/* }}} */
1610
1611/* {{{ proto public bool ReflectionFunction::isClosure()
1612   Returns whether this is a closure */
1613ZEND_METHOD(reflection_function, isClosure)
1614{
1615	reflection_object *intern;
1616	zend_function *fptr;
1617
1618	if (zend_parse_parameters_none() == FAILURE) {
1619		return;
1620	}
1621	GET_REFLECTION_OBJECT_PTR(fptr);
1622	RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_CLOSURE);
1623}
1624/* }}} */
1625
1626/* {{{ proto public bool ReflectionFunction::getClosureThis()
1627   Returns this pointer bound to closure */
1628ZEND_METHOD(reflection_function, getClosureThis)
1629{
1630	reflection_object *intern;
1631	zval* closure_this;
1632
1633	if (zend_parse_parameters_none() == FAILURE) {
1634		return;
1635	}
1636	GET_REFLECTION_OBJECT();
1637	if (!Z_ISUNDEF(intern->obj)) {
1638		closure_this = zend_get_closure_this_ptr(&intern->obj);
1639		if (!Z_ISUNDEF_P(closure_this)) {
1640			ZVAL_COPY(return_value, closure_this);
1641		}
1642	}
1643}
1644/* }}} */
1645
1646/* {{{ proto public ReflectionClass ReflectionFunction::getClosureScopeClass()
1647   Returns the scope associated to the closure */
1648ZEND_METHOD(reflection_function, getClosureScopeClass)
1649{
1650	reflection_object *intern;
1651	const zend_function *closure_func;
1652
1653	if (zend_parse_parameters_none() == FAILURE) {
1654		return;
1655	}
1656	GET_REFLECTION_OBJECT();
1657	if (!Z_ISUNDEF(intern->obj)) {
1658		closure_func = zend_get_closure_method_def(&intern->obj);
1659		if (closure_func && closure_func->common.scope) {
1660			zend_reflection_class_factory(closure_func->common.scope, return_value);
1661		}
1662	}
1663}
1664/* }}} */
1665
1666/* {{{ proto public mixed ReflectionFunction::getClosure()
1667   Returns a dynamically created closure for the function */
1668ZEND_METHOD(reflection_function, getClosure)
1669{
1670	reflection_object *intern;
1671	zend_function *fptr;
1672
1673	if (zend_parse_parameters_none() == FAILURE) {
1674		return;
1675	}
1676	GET_REFLECTION_OBJECT_PTR(fptr);
1677
1678	if (!Z_ISUNDEF(intern->obj)) {
1679		/* Closures are immutable objects */
1680		ZVAL_COPY(return_value, &intern->obj);
1681	} else {
1682		zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL);
1683	}
1684}
1685/* }}} */
1686
1687/* {{{ proto public bool ReflectionFunction::isInternal()
1688   Returns whether this is an internal function */
1689ZEND_METHOD(reflection_function, isInternal)
1690{
1691	reflection_object *intern;
1692	zend_function *fptr;
1693
1694	if (zend_parse_parameters_none() == FAILURE) {
1695		return;
1696	}
1697	GET_REFLECTION_OBJECT_PTR(fptr);
1698	RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION);
1699}
1700/* }}} */
1701
1702/* {{{ proto public bool ReflectionFunction::isUserDefined()
1703   Returns whether this is a user-defined function */
1704ZEND_METHOD(reflection_function, isUserDefined)
1705{
1706	reflection_object *intern;
1707	zend_function *fptr;
1708
1709	if (zend_parse_parameters_none() == FAILURE) {
1710		return;
1711	}
1712	GET_REFLECTION_OBJECT_PTR(fptr);
1713	RETURN_BOOL(fptr->type == ZEND_USER_FUNCTION);
1714}
1715/* }}} */
1716
1717/* {{{ proto public bool ReflectionFunction::isDisabled()
1718   Returns whether this function has been disabled or not */
1719ZEND_METHOD(reflection_function, isDisabled)
1720{
1721	reflection_object *intern;
1722	zend_function *fptr;
1723
1724	GET_REFLECTION_OBJECT_PTR(fptr);
1725	RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.handler == zif_display_disabled_function);
1726}
1727/* }}} */
1728
1729/* {{{ proto public string ReflectionFunction::getFileName()
1730   Returns the filename of the file this function was declared in */
1731ZEND_METHOD(reflection_function, getFileName)
1732{
1733	reflection_object *intern;
1734	zend_function *fptr;
1735
1736	if (zend_parse_parameters_none() == FAILURE) {
1737		return;
1738	}
1739	GET_REFLECTION_OBJECT_PTR(fptr);
1740	if (fptr->type == ZEND_USER_FUNCTION) {
1741		RETURN_STR_COPY(fptr->op_array.filename);
1742	}
1743	RETURN_FALSE;
1744}
1745/* }}} */
1746
1747/* {{{ proto public int ReflectionFunction::getStartLine()
1748   Returns the line this function's declaration starts at */
1749ZEND_METHOD(reflection_function, getStartLine)
1750{
1751	reflection_object *intern;
1752	zend_function *fptr;
1753
1754	if (zend_parse_parameters_none() == FAILURE) {
1755		return;
1756	}
1757	GET_REFLECTION_OBJECT_PTR(fptr);
1758	if (fptr->type == ZEND_USER_FUNCTION) {
1759		RETURN_LONG(fptr->op_array.line_start);
1760	}
1761	RETURN_FALSE;
1762}
1763/* }}} */
1764
1765/* {{{ proto public int ReflectionFunction::getEndLine()
1766   Returns the line this function's declaration ends at */
1767ZEND_METHOD(reflection_function, getEndLine)
1768{
1769	reflection_object *intern;
1770	zend_function *fptr;
1771
1772	if (zend_parse_parameters_none() == FAILURE) {
1773		return;
1774	}
1775	GET_REFLECTION_OBJECT_PTR(fptr);
1776	if (fptr->type == ZEND_USER_FUNCTION) {
1777		RETURN_LONG(fptr->op_array.line_end);
1778	}
1779	RETURN_FALSE;
1780}
1781/* }}} */
1782
1783/* {{{ proto public string ReflectionFunction::getDocComment()
1784   Returns the doc comment for this function */
1785ZEND_METHOD(reflection_function, getDocComment)
1786{
1787	reflection_object *intern;
1788	zend_function *fptr;
1789
1790	if (zend_parse_parameters_none() == FAILURE) {
1791		return;
1792	}
1793	GET_REFLECTION_OBJECT_PTR(fptr);
1794	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
1795		RETURN_STR_COPY(fptr->op_array.doc_comment);
1796	}
1797	RETURN_FALSE;
1798}
1799/* }}} */
1800
1801/* {{{ proto public array ReflectionFunction::getStaticVariables()
1802   Returns an associative array containing this function's static variables and their values */
1803ZEND_METHOD(reflection_function, getStaticVariables)
1804{
1805	reflection_object *intern;
1806	zend_function *fptr;
1807	zval *val;
1808
1809	if (zend_parse_parameters_none() == FAILURE) {
1810		return;
1811	}
1812	GET_REFLECTION_OBJECT_PTR(fptr);
1813
1814	/* Return an empty array in case no static variables exist */
1815	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
1816		array_init(return_value);
1817		if (GC_REFCOUNT(fptr->op_array.static_variables) > 1) {
1818			if (!(GC_FLAGS(fptr->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
1819				GC_DELREF(fptr->op_array.static_variables);
1820			}
1821			fptr->op_array.static_variables = zend_array_dup(fptr->op_array.static_variables);
1822		}
1823		ZEND_HASH_FOREACH_VAL(fptr->op_array.static_variables, val) {
1824			if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) {
1825				return;
1826			}
1827		} ZEND_HASH_FOREACH_END();
1828		zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, zval_add_ref);
1829	} else {
1830		ZVAL_EMPTY_ARRAY(return_value);
1831	}
1832}
1833/* }}} */
1834
1835/* {{{ proto public mixed ReflectionFunction::invoke([mixed* args])
1836   Invokes the function */
1837ZEND_METHOD(reflection_function, invoke)
1838{
1839	zval retval;
1840	zval *params = NULL;
1841	int result, num_args = 0;
1842	zend_fcall_info fci;
1843	zend_fcall_info_cache fcc;
1844	reflection_object *intern;
1845	zend_function *fptr;
1846
1847	GET_REFLECTION_OBJECT_PTR(fptr);
1848
1849	if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &params, &num_args) == FAILURE) {
1850		return;
1851	}
1852
1853	fci.size = sizeof(fci);
1854	ZVAL_UNDEF(&fci.function_name);
1855	fci.object = NULL;
1856	fci.retval = &retval;
1857	fci.param_count = num_args;
1858	fci.params = params;
1859	fci.no_separation = 1;
1860
1861	fcc.function_handler = fptr;
1862	fcc.called_scope = NULL;
1863	fcc.object = NULL;
1864
1865	if (!Z_ISUNDEF(intern->obj)) {
1866		Z_OBJ_HT(intern->obj)->get_closure(
1867			&intern->obj, &fcc.called_scope, &fcc.function_handler, &fcc.object);
1868	}
1869
1870	result = zend_call_function(&fci, &fcc);
1871
1872	if (result == FAILURE) {
1873		zend_throw_exception_ex(reflection_exception_ptr, 0,
1874			"Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name));
1875		return;
1876	}
1877
1878	if (Z_TYPE(retval) != IS_UNDEF) {
1879		if (Z_ISREF(retval)) {
1880			zend_unwrap_reference(&retval);
1881		}
1882		ZVAL_COPY_VALUE(return_value, &retval);
1883	}
1884}
1885/* }}} */
1886
1887/* {{{ proto public mixed ReflectionFunction::invokeArgs(array args)
1888   Invokes the function and pass its arguments as array. */
1889ZEND_METHOD(reflection_function, invokeArgs)
1890{
1891	zval retval;
1892	zval *params, *val;
1893	int result;
1894	int i, argc;
1895	zend_fcall_info fci;
1896	zend_fcall_info_cache fcc;
1897	reflection_object *intern;
1898	zend_function *fptr;
1899	zval *param_array;
1900
1901	GET_REFLECTION_OBJECT_PTR(fptr);
1902
1903	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &param_array) == FAILURE) {
1904		return;
1905	}
1906
1907	argc = zend_hash_num_elements(Z_ARRVAL_P(param_array));
1908
1909	params = safe_emalloc(sizeof(zval), argc, 0);
1910	argc = 0;
1911	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(param_array), val) {
1912		ZVAL_COPY(&params[argc], val);
1913		argc++;
1914	} ZEND_HASH_FOREACH_END();
1915
1916	fci.size = sizeof(fci);
1917	ZVAL_UNDEF(&fci.function_name);
1918	fci.object = NULL;
1919	fci.retval = &retval;
1920	fci.param_count = argc;
1921	fci.params = params;
1922	fci.no_separation = 1;
1923
1924	fcc.function_handler = fptr;
1925	fcc.called_scope = NULL;
1926	fcc.object = NULL;
1927
1928	if (!Z_ISUNDEF(intern->obj)) {
1929		Z_OBJ_HT(intern->obj)->get_closure(
1930			&intern->obj, &fcc.called_scope, &fcc.function_handler, &fcc.object);
1931	}
1932
1933	result = zend_call_function(&fci, &fcc);
1934
1935	for (i = 0; i < argc; i++) {
1936		zval_ptr_dtor(&params[i]);
1937	}
1938	efree(params);
1939
1940	if (result == FAILURE) {
1941		zend_throw_exception_ex(reflection_exception_ptr, 0,
1942			"Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name));
1943		return;
1944	}
1945
1946	if (Z_TYPE(retval) != IS_UNDEF) {
1947		if (Z_ISREF(retval)) {
1948			zend_unwrap_reference(&retval);
1949		}
1950		ZVAL_COPY_VALUE(return_value, &retval);
1951	}
1952}
1953/* }}} */
1954
1955/* {{{ proto public bool ReflectionFunction::returnsReference()
1956   Gets whether this function returns a reference */
1957ZEND_METHOD(reflection_function, returnsReference)
1958{
1959	reflection_object *intern;
1960	zend_function *fptr;
1961
1962	GET_REFLECTION_OBJECT_PTR(fptr);
1963
1964	RETURN_BOOL((fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0);
1965}
1966/* }}} */
1967
1968/* {{{ proto public bool ReflectionFunction::getNumberOfParameters()
1969   Gets the number of parameters */
1970ZEND_METHOD(reflection_function, getNumberOfParameters)
1971{
1972	reflection_object *intern;
1973	zend_function *fptr;
1974	uint32_t num_args;
1975
1976	GET_REFLECTION_OBJECT_PTR(fptr);
1977
1978	num_args = fptr->common.num_args;
1979	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
1980		num_args++;
1981	}
1982
1983	RETURN_LONG(num_args);
1984}
1985/* }}} */
1986
1987/* {{{ proto public bool ReflectionFunction::getNumberOfRequiredParameters()
1988   Gets the number of required parameters */
1989ZEND_METHOD(reflection_function, getNumberOfRequiredParameters)
1990{
1991	reflection_object *intern;
1992	zend_function *fptr;
1993
1994	GET_REFLECTION_OBJECT_PTR(fptr);
1995
1996	RETURN_LONG(fptr->common.required_num_args);
1997}
1998/* }}} */
1999
2000/* {{{ proto public ReflectionParameter[] ReflectionFunction::getParameters()
2001   Returns an array of parameter objects for this function */
2002ZEND_METHOD(reflection_function, getParameters)
2003{
2004	reflection_object *intern;
2005	zend_function *fptr;
2006	uint32_t i, num_args;
2007	struct _zend_arg_info *arg_info;
2008
2009	GET_REFLECTION_OBJECT_PTR(fptr);
2010
2011	arg_info= fptr->common.arg_info;
2012	num_args = fptr->common.num_args;
2013	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2014		num_args++;
2015	}
2016
2017	if (!num_args) {
2018		ZVAL_EMPTY_ARRAY(return_value);
2019		return;
2020	}
2021
2022	array_init(return_value);
2023	for (i = 0; i < num_args; i++) {
2024		zval parameter;
2025
2026		reflection_parameter_factory(
2027			_copy_function(fptr),
2028			Z_ISUNDEF(intern->obj) ? NULL : &intern->obj,
2029			arg_info,
2030			i,
2031			i < fptr->common.required_num_args,
2032			&parameter
2033		);
2034		add_next_index_zval(return_value, &parameter);
2035
2036		arg_info++;
2037	}
2038}
2039/* }}} */
2040
2041/* {{{ proto public ReflectionExtension|NULL ReflectionFunction::getExtension()
2042   Returns NULL or the extension the function belongs to */
2043ZEND_METHOD(reflection_function, getExtension)
2044{
2045	reflection_object *intern;
2046	zend_function *fptr;
2047	zend_internal_function *internal;
2048
2049	GET_REFLECTION_OBJECT_PTR(fptr);
2050
2051	if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2052		RETURN_NULL();
2053	}
2054
2055	internal = (zend_internal_function *)fptr;
2056	if (internal->module) {
2057		reflection_extension_factory(return_value, internal->module->name);
2058	} else {
2059		RETURN_NULL();
2060	}
2061}
2062/* }}} */
2063
2064/* {{{ proto public string|false ReflectionFunction::getExtensionName()
2065   Returns false or the name of the extension the function belongs to */
2066ZEND_METHOD(reflection_function, getExtensionName)
2067{
2068	reflection_object *intern;
2069	zend_function *fptr;
2070	zend_internal_function *internal;
2071
2072	GET_REFLECTION_OBJECT_PTR(fptr);
2073
2074	if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2075		RETURN_FALSE;
2076	}
2077
2078	internal = (zend_internal_function *)fptr;
2079	if (internal->module) {
2080		RETURN_STRING(internal->module->name);
2081	} else {
2082		RETURN_FALSE;
2083	}
2084}
2085/* }}} */
2086
2087/* {{{ proto public void ReflectionGenerator::__construct(object Generator) */
2088ZEND_METHOD(reflection_generator, __construct)
2089{
2090	zval *generator, *object;
2091	reflection_object *intern;
2092	zend_execute_data *ex;
2093
2094	object = getThis();
2095	intern = Z_REFLECTION_P(object);
2096
2097	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) {
2098		return;
2099	}
2100
2101	ex = ((zend_generator *) Z_OBJ_P(generator))->execute_data;
2102	if (!ex) {
2103		_DO_THROW("Cannot create ReflectionGenerator based on a terminated Generator");
2104		return;
2105	}
2106
2107	intern->ref_type = REF_TYPE_GENERATOR;
2108	ZVAL_COPY(&intern->obj, generator);
2109	intern->ce = zend_ce_generator;
2110}
2111/* }}} */
2112
2113#define REFLECTION_CHECK_VALID_GENERATOR(ex) \
2114	if (!ex) { \
2115		_DO_THROW("Cannot fetch information from a terminated Generator"); \
2116		return; \
2117	}
2118
2119/* {{{ proto public array ReflectionGenerator::getTrace($options = DEBUG_BACKTRACE_PROVIDE_OBJECT) */
2120ZEND_METHOD(reflection_generator, getTrace)
2121{
2122	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
2123	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj);
2124	zend_generator *root_generator;
2125	zend_execute_data *ex_backup = EG(current_execute_data);
2126	zend_execute_data *ex = generator->execute_data;
2127	zend_execute_data *root_prev = NULL, *cur_prev;
2128
2129	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &options) == FAILURE) {
2130		return;
2131	}
2132
2133	REFLECTION_CHECK_VALID_GENERATOR(ex)
2134
2135	root_generator = zend_generator_get_current(generator);
2136
2137	cur_prev = generator->execute_data->prev_execute_data;
2138	if (generator == root_generator) {
2139		generator->execute_data->prev_execute_data = NULL;
2140	} else {
2141		root_prev = root_generator->execute_data->prev_execute_data;
2142		generator->execute_fake.prev_execute_data = NULL;
2143		root_generator->execute_data->prev_execute_data = &generator->execute_fake;
2144	}
2145
2146	EG(current_execute_data) = root_generator->execute_data;
2147	zend_fetch_debug_backtrace(return_value, 0, options, 0);
2148	EG(current_execute_data) = ex_backup;
2149
2150	root_generator->execute_data->prev_execute_data = root_prev;
2151	generator->execute_data->prev_execute_data = cur_prev;
2152}
2153/* }}} */
2154
2155/* {{{ proto public int ReflectionGenerator::getExecutingLine() */
2156ZEND_METHOD(reflection_generator, getExecutingLine)
2157{
2158	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj);
2159	zend_execute_data *ex = generator->execute_data;
2160
2161	if (zend_parse_parameters_none() == FAILURE) {
2162		return;
2163	}
2164
2165	REFLECTION_CHECK_VALID_GENERATOR(ex)
2166
2167	ZVAL_LONG(return_value, ex->opline->lineno);
2168}
2169/* }}} */
2170
2171/* {{{ proto public string ReflectionGenerator::getExecutingFile() */
2172ZEND_METHOD(reflection_generator, getExecutingFile)
2173{
2174	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj);
2175	zend_execute_data *ex = generator->execute_data;
2176
2177	if (zend_parse_parameters_none() == FAILURE) {
2178		return;
2179	}
2180
2181	REFLECTION_CHECK_VALID_GENERATOR(ex)
2182
2183	ZVAL_STR_COPY(return_value, ex->func->op_array.filename);
2184}
2185/* }}} */
2186
2187/* {{{ proto public ReflectionFunctionAbstract ReflectionGenerator::getFunction() */
2188ZEND_METHOD(reflection_generator, getFunction)
2189{
2190	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj);
2191	zend_execute_data *ex = generator->execute_data;
2192
2193	if (zend_parse_parameters_none() == FAILURE) {
2194		return;
2195	}
2196
2197	REFLECTION_CHECK_VALID_GENERATOR(ex)
2198
2199	if (ex->func->common.fn_flags & ZEND_ACC_CLOSURE) {
2200		zval closure;
2201		ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(ex->func));
2202		reflection_function_factory(ex->func, &closure, return_value);
2203	} else if (ex->func->op_array.scope) {
2204		reflection_method_factory(ex->func->op_array.scope, ex->func, NULL, return_value);
2205	} else {
2206		reflection_function_factory(ex->func, NULL, return_value);
2207	}
2208}
2209/* }}} */
2210
2211/* {{{ proto public object ReflectionGenerator::getThis() */
2212ZEND_METHOD(reflection_generator, getThis)
2213{
2214	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj);
2215	zend_execute_data *ex = generator->execute_data;
2216
2217	if (zend_parse_parameters_none() == FAILURE) {
2218		return;
2219	}
2220
2221	REFLECTION_CHECK_VALID_GENERATOR(ex)
2222
2223	if (Z_TYPE(ex->This) == IS_OBJECT) {
2224		ZVAL_COPY(return_value, &ex->This);
2225	} else {
2226		ZVAL_NULL(return_value);
2227	}
2228}
2229/* }}} */
2230
2231/* {{{ proto public Generator ReflectionGenerator::getExecutingGenerator() */
2232ZEND_METHOD(reflection_generator, getExecutingGenerator)
2233{
2234	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(getThis())->obj);
2235	zend_execute_data *ex = generator->execute_data;
2236	zend_generator *current;
2237
2238	if (zend_parse_parameters_none() == FAILURE) {
2239		return;
2240	}
2241
2242	REFLECTION_CHECK_VALID_GENERATOR(ex)
2243
2244	current = zend_generator_get_current(generator);
2245	GC_ADDREF(&current->std);
2246
2247	ZVAL_OBJ(return_value, (zend_object *) current);
2248}
2249/* }}} */
2250
2251/* {{{ proto public static mixed ReflectionParameter::export(mixed function, mixed parameter [, bool return]) throws ReflectionException
2252   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
2253ZEND_METHOD(reflection_parameter, export)
2254{
2255	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_parameter_ptr, 2);
2256}
2257/* }}} */
2258
2259/* {{{ proto public void ReflectionParameter::__construct(mixed function, mixed parameter)
2260   Constructor. Throws an Exception in case the given method does not exist */
2261ZEND_METHOD(reflection_parameter, __construct)
2262{
2263	parameter_reference *ref;
2264	zval *reference, *parameter;
2265	zval *object;
2266	zval name;
2267	reflection_object *intern;
2268	zend_function *fptr;
2269	struct _zend_arg_info *arg_info;
2270	int position;
2271	uint32_t num_args;
2272	zend_class_entry *ce = NULL;
2273	zend_bool is_closure = 0;
2274
2275	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zz", &reference, &parameter) == FAILURE) {
2276		return;
2277	}
2278
2279	object = getThis();
2280	intern = Z_REFLECTION_P(object);
2281
2282	/* First, find the function */
2283	switch (Z_TYPE_P(reference)) {
2284		case IS_STRING: {
2285				size_t lcname_len;
2286				char *lcname;
2287
2288				lcname_len = Z_STRLEN_P(reference);
2289				lcname = zend_str_tolower_dup(Z_STRVAL_P(reference), lcname_len);
2290				if ((fptr = zend_hash_str_find_ptr(EG(function_table), lcname, lcname_len)) == NULL) {
2291					efree(lcname);
2292					zend_throw_exception_ex(reflection_exception_ptr, 0,
2293						"Function %s() does not exist", Z_STRVAL_P(reference));
2294					return;
2295				}
2296				efree(lcname);
2297			}
2298			ce = fptr->common.scope;
2299			break;
2300
2301		case IS_ARRAY: {
2302				zval *classref;
2303				zval *method;
2304				size_t lcname_len;
2305				char *lcname;
2306
2307				if (((classref =zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
2308					|| ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL))
2309				{
2310					_DO_THROW("Expected array($object, $method) or array($classname, $method)");
2311					/* returns out of this function */
2312				}
2313
2314				if (Z_TYPE_P(classref) == IS_OBJECT) {
2315					ce = Z_OBJCE_P(classref);
2316				} else {
2317					convert_to_string_ex(classref);
2318					if ((ce = zend_lookup_class(Z_STR_P(classref))) == NULL) {
2319						zend_throw_exception_ex(reflection_exception_ptr, 0,
2320								"Class %s does not exist", Z_STRVAL_P(classref));
2321						return;
2322					}
2323				}
2324
2325				convert_to_string_ex(method);
2326				lcname_len = Z_STRLEN_P(method);
2327				lcname = zend_str_tolower_dup(Z_STRVAL_P(method), lcname_len);
2328				if (ce == zend_ce_closure && Z_TYPE_P(classref) == IS_OBJECT
2329					&& (lcname_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
2330					&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
2331					&& (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
2332				{
2333					/* nothing to do. don't set is_closure since is the invoke handler,
2334					   not the closure itself */
2335				} else if ((fptr = zend_hash_str_find_ptr(&ce->function_table, lcname, lcname_len)) == NULL) {
2336					efree(lcname);
2337					zend_throw_exception_ex(reflection_exception_ptr, 0,
2338						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), Z_STRVAL_P(method));
2339					return;
2340				}
2341				efree(lcname);
2342			}
2343			break;
2344
2345		case IS_OBJECT: {
2346				ce = Z_OBJCE_P(reference);
2347
2348				if (instanceof_function(ce, zend_ce_closure)) {
2349					fptr = (zend_function *)zend_get_closure_method_def(reference);
2350					Z_ADDREF_P(reference);
2351					is_closure = 1;
2352				} else if ((fptr = zend_hash_str_find_ptr(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME))) == NULL) {
2353					zend_throw_exception_ex(reflection_exception_ptr, 0,
2354						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME);
2355					return;
2356				}
2357			}
2358			break;
2359
2360		default:
2361			_DO_THROW("The parameter class is expected to be either a string, an array(class, method) or a callable object");
2362			/* returns out of this function */
2363	}
2364
2365	/* Now, search for the parameter */
2366	arg_info = fptr->common.arg_info;
2367	num_args = fptr->common.num_args;
2368	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2369		num_args++;
2370	}
2371	if (Z_TYPE_P(parameter) == IS_LONG) {
2372		position= (int)Z_LVAL_P(parameter);
2373		if (position < 0 || (uint32_t)position >= num_args) {
2374			if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2375				if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
2376					zend_string_release_ex(fptr->common.function_name, 0);
2377				}
2378				zend_free_trampoline(fptr);
2379			}
2380			if (is_closure) {
2381				zval_ptr_dtor(reference);
2382			}
2383			_DO_THROW("The parameter specified by its offset could not be found");
2384			/* returns out of this function */
2385		}
2386	} else {
2387		uint32_t i;
2388
2389		position= -1;
2390		convert_to_string_ex(parameter);
2391		if (fptr->type == ZEND_INTERNAL_FUNCTION &&
2392		    !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
2393			for (i = 0; i < num_args; i++) {
2394				if (arg_info[i].name) {
2395					if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, Z_STRVAL_P(parameter)) == 0) {
2396						position= i;
2397						break;
2398					}
2399
2400				}
2401			}
2402		} else {
2403			for (i = 0; i < num_args; i++) {
2404				if (arg_info[i].name) {
2405					if (strcmp(ZSTR_VAL(arg_info[i].name), Z_STRVAL_P(parameter)) == 0) {
2406						position= i;
2407						break;
2408					}
2409				}
2410			}
2411		}
2412		if (position == -1) {
2413			if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2414				if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
2415					zend_string_release_ex(fptr->common.function_name, 0);
2416				}
2417				zend_free_trampoline(fptr);
2418			}
2419			if (is_closure) {
2420				zval_ptr_dtor(reference);
2421			}
2422			_DO_THROW("The parameter specified by its name could not be found");
2423			/* returns out of this function */
2424		}
2425	}
2426
2427	if (arg_info[position].name) {
2428		if (fptr->type == ZEND_INTERNAL_FUNCTION &&
2429		    !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
2430			ZVAL_STRING(&name, ((zend_internal_arg_info*)arg_info)[position].name);
2431		} else {
2432			ZVAL_STR_COPY(&name, arg_info[position].name);
2433		}
2434	} else {
2435		ZVAL_NULL(&name);
2436	}
2437	reflection_update_property_name(object, &name);
2438
2439	ref = (parameter_reference*) emalloc(sizeof(parameter_reference));
2440	ref->arg_info = &arg_info[position];
2441	ref->offset = (uint32_t)position;
2442	ref->required = position < fptr->common.required_num_args;
2443	ref->fptr = fptr;
2444	/* TODO: copy fptr */
2445	intern->ptr = ref;
2446	intern->ref_type = REF_TYPE_PARAMETER;
2447	intern->ce = ce;
2448	if (reference && is_closure) {
2449		ZVAL_COPY_VALUE(&intern->obj, reference);
2450	}
2451}
2452/* }}} */
2453
2454/* {{{ proto public string ReflectionParameter::__toString()
2455   Returns a string representation */
2456ZEND_METHOD(reflection_parameter, __toString)
2457{
2458	reflection_object *intern;
2459	parameter_reference *param;
2460	smart_str str = {0};
2461
2462	if (zend_parse_parameters_none() == FAILURE) {
2463		return;
2464	}
2465	GET_REFLECTION_OBJECT_PTR(param);
2466	_parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "");
2467	RETURN_STR(smart_str_extract(&str));
2468}
2469
2470/* }}} */
2471
2472/* {{{ proto public string ReflectionParameter::getName()
2473   Returns this parameters's name */
2474ZEND_METHOD(reflection_parameter, getName)
2475{
2476	if (zend_parse_parameters_none() == FAILURE) {
2477		return;
2478	}
2479	_default_get_name(getThis(), return_value);
2480}
2481/* }}} */
2482
2483/* {{{ proto public ReflectionFunction ReflectionParameter::getDeclaringFunction()
2484   Returns the ReflectionFunction for the function of this parameter */
2485ZEND_METHOD(reflection_parameter, getDeclaringFunction)
2486{
2487	reflection_object *intern;
2488	parameter_reference *param;
2489
2490	if (zend_parse_parameters_none() == FAILURE) {
2491		return;
2492	}
2493	GET_REFLECTION_OBJECT_PTR(param);
2494
2495	if (!param->fptr->common.scope) {
2496		reflection_function_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2497	} else {
2498		reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2499	}
2500}
2501/* }}} */
2502
2503/* {{{ proto public ReflectionClass|NULL ReflectionParameter::getDeclaringClass()
2504   Returns in which class this parameter is defined (not the type of the parameter) */
2505ZEND_METHOD(reflection_parameter, getDeclaringClass)
2506{
2507	reflection_object *intern;
2508	parameter_reference *param;
2509
2510	if (zend_parse_parameters_none() == FAILURE) {
2511		return;
2512	}
2513	GET_REFLECTION_OBJECT_PTR(param);
2514
2515	if (param->fptr->common.scope) {
2516		zend_reflection_class_factory(param->fptr->common.scope, return_value);
2517	}
2518}
2519/* }}} */
2520
2521/* {{{ proto public ReflectionClass|NULL ReflectionParameter::getClass()
2522   Returns this parameters's class hint or NULL if there is none */
2523ZEND_METHOD(reflection_parameter, getClass)
2524{
2525	reflection_object *intern;
2526	parameter_reference *param;
2527	zend_class_entry *ce;
2528
2529	if (zend_parse_parameters_none() == FAILURE) {
2530		return;
2531	}
2532	GET_REFLECTION_OBJECT_PTR(param);
2533
2534	if (ZEND_TYPE_IS_CLASS(param->arg_info->type)) {
2535		/* Class name is stored as a string, we might also get "self" or "parent"
2536		 * - For "self", simply use the function scope. If scope is NULL then
2537		 *   the function is global and thus self does not make any sense
2538		 *
2539		 * - For "parent", use the function scope's parent. If scope is NULL then
2540		 *   the function is global and thus parent does not make any sense.
2541		 *   If the parent is NULL then the class does not extend anything and
2542		 *   thus parent does not make any sense, either.
2543		 *
2544		 * TODO: Think about moving these checks to the compiler or some sort of
2545		 * lint-mode.
2546		 */
2547		zend_string *class_name;
2548
2549		class_name = ZEND_TYPE_NAME(param->arg_info->type);
2550		if (0 == zend_binary_strcasecmp(ZSTR_VAL(class_name), ZSTR_LEN(class_name), "self", sizeof("self")- 1)) {
2551			ce = param->fptr->common.scope;
2552			if (!ce) {
2553				zend_throw_exception_ex(reflection_exception_ptr, 0,
2554					"Parameter uses 'self' as type hint but function is not a class member!");
2555				return;
2556			}
2557		} else if (0 == zend_binary_strcasecmp(ZSTR_VAL(class_name), ZSTR_LEN(class_name), "parent", sizeof("parent")- 1)) {
2558			ce = param->fptr->common.scope;
2559			if (!ce) {
2560				zend_throw_exception_ex(reflection_exception_ptr, 0,
2561					"Parameter uses 'parent' as type hint but function is not a class member!");
2562				return;
2563			}
2564			if (!ce->parent) {
2565				zend_throw_exception_ex(reflection_exception_ptr, 0,
2566					"Parameter uses 'parent' as type hint although class does not have a parent!");
2567				return;
2568			}
2569			ce = ce->parent;
2570		} else {
2571			ce = zend_lookup_class(class_name);
2572			if (!ce) {
2573				zend_throw_exception_ex(reflection_exception_ptr, 0,
2574					"Class %s does not exist", ZSTR_VAL(class_name));
2575				return;
2576			}
2577		}
2578		zend_reflection_class_factory(ce, return_value);
2579	}
2580}
2581/* }}} */
2582
2583/* {{{ proto public bool ReflectionParameter::hasType()
2584   Returns whether parameter has a type */
2585ZEND_METHOD(reflection_parameter, hasType)
2586{
2587	reflection_object *intern;
2588	parameter_reference *param;
2589
2590	if (zend_parse_parameters_none() == FAILURE) {
2591		return;
2592	}
2593	GET_REFLECTION_OBJECT_PTR(param);
2594
2595	RETVAL_BOOL(ZEND_TYPE_IS_SET(param->arg_info->type));
2596}
2597/* }}} */
2598
2599/* {{{ proto public ReflectionType ReflectionParameter::getType()
2600   Returns the type associated with the parameter */
2601ZEND_METHOD(reflection_parameter, getType)
2602{
2603	reflection_object *intern;
2604	parameter_reference *param;
2605
2606	if (zend_parse_parameters_none() == FAILURE) {
2607		return;
2608	}
2609	GET_REFLECTION_OBJECT_PTR(param);
2610
2611	if (!ZEND_TYPE_IS_SET(param->arg_info->type)) {
2612		RETURN_NULL();
2613	}
2614	reflection_type_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, param->arg_info, return_value);
2615}
2616/* }}} */
2617
2618/* {{{ proto public bool ReflectionParameter::isArray()
2619   Returns whether parameter MUST be an array */
2620ZEND_METHOD(reflection_parameter, isArray)
2621{
2622	reflection_object *intern;
2623	parameter_reference *param;
2624
2625	if (zend_parse_parameters_none() == FAILURE) {
2626		return;
2627	}
2628	GET_REFLECTION_OBJECT_PTR(param);
2629
2630	RETVAL_BOOL(ZEND_TYPE_CODE(param->arg_info->type) == IS_ARRAY);
2631}
2632/* }}} */
2633
2634/* {{{ proto public bool ReflectionParameter::isCallable()
2635   Returns whether parameter MUST be callable */
2636ZEND_METHOD(reflection_parameter, isCallable)
2637{
2638	reflection_object *intern;
2639	parameter_reference *param;
2640
2641	if (zend_parse_parameters_none() == FAILURE) {
2642		return;
2643	}
2644	GET_REFLECTION_OBJECT_PTR(param);
2645
2646	RETVAL_BOOL(ZEND_TYPE_CODE(param->arg_info->type) == IS_CALLABLE);
2647}
2648/* }}} */
2649
2650/* {{{ proto public bool ReflectionParameter::allowsNull()
2651   Returns whether NULL is allowed as this parameters's value */
2652ZEND_METHOD(reflection_parameter, allowsNull)
2653{
2654	reflection_object *intern;
2655	parameter_reference *param;
2656
2657	if (zend_parse_parameters_none() == FAILURE) {
2658		return;
2659	}
2660	GET_REFLECTION_OBJECT_PTR(param);
2661
2662	RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->arg_info->type));
2663}
2664/* }}} */
2665
2666/* {{{ proto public bool ReflectionParameter::isPassedByReference()
2667   Returns whether this parameters is passed to by reference */
2668ZEND_METHOD(reflection_parameter, isPassedByReference)
2669{
2670	reflection_object *intern;
2671	parameter_reference *param;
2672
2673	if (zend_parse_parameters_none() == FAILURE) {
2674		return;
2675	}
2676	GET_REFLECTION_OBJECT_PTR(param);
2677
2678	RETVAL_BOOL(param->arg_info->pass_by_reference);
2679}
2680/* }}} */
2681
2682/* {{{ proto public bool ReflectionParameter::canBePassedByValue()
2683   Returns whether this parameter can be passed by value */
2684ZEND_METHOD(reflection_parameter, canBePassedByValue)
2685{
2686	reflection_object *intern;
2687	parameter_reference *param;
2688
2689	if (zend_parse_parameters_none() == FAILURE) {
2690		return;
2691	}
2692	GET_REFLECTION_OBJECT_PTR(param);
2693
2694	/* true if it's ZEND_SEND_BY_VAL or ZEND_SEND_PREFER_REF */
2695	RETVAL_BOOL(param->arg_info->pass_by_reference != ZEND_SEND_BY_REF);
2696}
2697/* }}} */
2698
2699/* {{{ proto public bool ReflectionParameter::getPosition()
2700   Returns whether this parameter is an optional parameter */
2701ZEND_METHOD(reflection_parameter, getPosition)
2702{
2703	reflection_object *intern;
2704	parameter_reference *param;
2705
2706	if (zend_parse_parameters_none() == FAILURE) {
2707		return;
2708	}
2709	GET_REFLECTION_OBJECT_PTR(param);
2710
2711	RETVAL_LONG(param->offset);
2712}
2713/* }}} */
2714
2715/* {{{ proto public bool ReflectionParameter::isOptional()
2716   Returns whether this parameter is an optional parameter */
2717ZEND_METHOD(reflection_parameter, isOptional)
2718{
2719	reflection_object *intern;
2720	parameter_reference *param;
2721
2722	if (zend_parse_parameters_none() == FAILURE) {
2723		return;
2724	}
2725	GET_REFLECTION_OBJECT_PTR(param);
2726
2727	RETVAL_BOOL(!param->required);
2728}
2729/* }}} */
2730
2731/* {{{ proto public bool ReflectionParameter::isDefaultValueAvailable()
2732   Returns whether the default value of this parameter is available */
2733ZEND_METHOD(reflection_parameter, isDefaultValueAvailable)
2734{
2735	reflection_object *intern;
2736	parameter_reference *param;
2737	zend_op *precv;
2738
2739	if (zend_parse_parameters_none() == FAILURE) {
2740		return;
2741	}
2742	GET_REFLECTION_OBJECT_PTR(param);
2743
2744	if (param->fptr->type != ZEND_USER_FUNCTION)
2745	{
2746		RETURN_FALSE;
2747	}
2748
2749	precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
2750	if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
2751		RETURN_FALSE;
2752	}
2753	RETURN_TRUE;
2754}
2755/* }}} */
2756
2757/* {{{ proto public bool ReflectionParameter::getDefaultValue()
2758   Returns the default value of this parameter or throws an exception */
2759ZEND_METHOD(reflection_parameter, getDefaultValue)
2760{
2761	parameter_reference *param;
2762	zend_op *precv;
2763
2764	if (zend_parse_parameters_none() == FAILURE) {
2765		return;
2766	}
2767
2768	param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2769	if (!param) {
2770		return;
2771	}
2772
2773	precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2774	if (!precv) {
2775		return;
2776	}
2777
2778	ZVAL_COPY(return_value, RT_CONSTANT(precv, precv->op2));
2779	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
2780		zval_update_constant_ex(return_value, param->fptr->common.scope);
2781	}
2782}
2783/* }}} */
2784
2785/* {{{ proto public bool ReflectionParameter::isDefaultValueConstant()
2786   Returns whether the default value of this parameter is constant */
2787ZEND_METHOD(reflection_parameter, isDefaultValueConstant)
2788{
2789	zend_op *precv;
2790	parameter_reference *param;
2791
2792	if (zend_parse_parameters_none() == FAILURE) {
2793		return;
2794	}
2795
2796	param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2797	if (!param) {
2798		RETURN_FALSE;
2799	}
2800
2801	precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2802	if (precv && Z_TYPE_P(RT_CONSTANT(precv, precv->op2)) == IS_CONSTANT_AST) {
2803		zend_ast *ast = Z_ASTVAL_P(RT_CONSTANT(precv, precv->op2));
2804
2805		if (ast->kind == ZEND_AST_CONSTANT
2806		 || ast->kind == ZEND_AST_CONSTANT_CLASS) {
2807			RETURN_TRUE;
2808		}
2809	}
2810
2811	RETURN_FALSE;
2812}
2813/* }}} */
2814
2815/* {{{ proto public mixed ReflectionParameter::getDefaultValueConstantName()
2816   Returns the default value's constant name if default value is constant or null */
2817ZEND_METHOD(reflection_parameter, getDefaultValueConstantName)
2818{
2819	zend_op *precv;
2820	parameter_reference *param;
2821
2822	if (zend_parse_parameters_none() == FAILURE) {
2823		return;
2824	}
2825
2826	param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2827	if (!param) {
2828		return;
2829	}
2830
2831	precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2832	if (precv && Z_TYPE_P(RT_CONSTANT(precv, precv->op2)) == IS_CONSTANT_AST) {
2833		zend_ast *ast = Z_ASTVAL_P(RT_CONSTANT(precv, precv->op2));
2834
2835		if (ast->kind == ZEND_AST_CONSTANT) {
2836			RETURN_STR_COPY(zend_ast_get_constant_name(ast));
2837		} else if (ast->kind == ZEND_AST_CONSTANT_CLASS) {
2838			RETURN_STRINGL("__CLASS__", sizeof("__CLASS__")-1);
2839		}
2840	}
2841}
2842/* }}} */
2843
2844/* {{{ proto public bool ReflectionParameter::isVariadic()
2845   Returns whether this parameter is a variadic parameter */
2846ZEND_METHOD(reflection_parameter, isVariadic)
2847{
2848	reflection_object *intern;
2849	parameter_reference *param;
2850
2851	if (zend_parse_parameters_none() == FAILURE) {
2852		return;
2853	}
2854	GET_REFLECTION_OBJECT_PTR(param);
2855
2856	RETVAL_BOOL(param->arg_info->is_variadic);
2857}
2858/* }}} */
2859
2860/* {{{ proto public bool ReflectionType::allowsNull()
2861  Returns whether parameter MAY be null */
2862ZEND_METHOD(reflection_type, allowsNull)
2863{
2864	reflection_object *intern;
2865	type_reference *param;
2866
2867	if (zend_parse_parameters_none() == FAILURE) {
2868		return;
2869	}
2870	GET_REFLECTION_OBJECT_PTR(param);
2871
2872	RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->arg_info->type));
2873}
2874/* }}} */
2875
2876/* {{{ proto public bool ReflectionType::isBuiltin()
2877  Returns whether parameter is a builtin type */
2878ZEND_METHOD(reflection_type, isBuiltin)
2879{
2880	reflection_object *intern;
2881	type_reference *param;
2882
2883	if (zend_parse_parameters_none() == FAILURE) {
2884		return;
2885	}
2886	GET_REFLECTION_OBJECT_PTR(param);
2887
2888	RETVAL_BOOL(ZEND_TYPE_IS_CODE(param->arg_info->type));
2889}
2890/* }}} */
2891
2892/* {{{ reflection_type_name */
2893static zend_string *reflection_type_name(type_reference *param) {
2894	if (ZEND_TYPE_IS_CLASS(param->arg_info->type)) {
2895		return zend_string_copy(ZEND_TYPE_NAME(param->arg_info->type));
2896	} else {
2897		char *name = zend_get_type_by_const(ZEND_TYPE_CODE(param->arg_info->type));
2898		return zend_string_init(name, strlen(name), 0);
2899	}
2900}
2901/* }}} */
2902
2903/* {{{ proto public string ReflectionType::__toString()
2904   Return the text of the type hint */
2905ZEND_METHOD(reflection_type, __toString)
2906{
2907	reflection_object *intern;
2908	type_reference *param;
2909
2910	if (zend_parse_parameters_none() == FAILURE) {
2911		return;
2912	}
2913	GET_REFLECTION_OBJECT_PTR(param);
2914
2915	RETURN_STR(reflection_type_name(param));
2916}
2917/* }}} */
2918
2919/* {{{ proto public string ReflectionNamedType::getName()
2920 Return the text of the type hint */
2921ZEND_METHOD(reflection_named_type, getName)
2922{
2923	reflection_object *intern;
2924	type_reference *param;
2925
2926	if (zend_parse_parameters_none() == FAILURE) {
2927		return;
2928	}
2929	GET_REFLECTION_OBJECT_PTR(param);
2930
2931	RETURN_STR(reflection_type_name(param));
2932}
2933/* }}} */
2934
2935/* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
2936   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
2937ZEND_METHOD(reflection_method, export)
2938{
2939	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_method_ptr, 2);
2940}
2941/* }}} */
2942
2943/* {{{ proto public void ReflectionMethod::__construct(mixed class_or_method [, string name])
2944   Constructor. Throws an Exception in case the given method does not exist */
2945ZEND_METHOD(reflection_method, __construct)
2946{
2947	zval name, *classname;
2948	zval *object, *orig_obj;
2949	reflection_object *intern;
2950	char *lcname;
2951	zend_class_entry *ce;
2952	zend_function *mptr;
2953	char *name_str, *tmp;
2954	size_t name_len, tmp_len;
2955	zval ztmp;
2956
2957	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "zs", &classname, &name_str, &name_len) == FAILURE) {
2958		if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
2959			return;
2960		}
2961
2962		if ((tmp = strstr(name_str, "::")) == NULL) {
2963			zend_throw_exception_ex(reflection_exception_ptr, 0,
2964				"Invalid method name %s", name_str);
2965			return;
2966		}
2967		classname = &ztmp;
2968		tmp_len = tmp - name_str;
2969		ZVAL_STRINGL(classname, name_str, tmp_len);
2970		name_len = name_len - (tmp_len + 2);
2971		name_str = tmp + 2;
2972		orig_obj = NULL;
2973	} else if (Z_TYPE_P(classname) == IS_OBJECT) {
2974		orig_obj = classname;
2975	} else {
2976		orig_obj = NULL;
2977	}
2978
2979	object = getThis();
2980	intern = Z_REFLECTION_P(object);
2981
2982	/* Find the class entry */
2983	switch (Z_TYPE_P(classname)) {
2984		case IS_STRING:
2985			if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
2986				if (!EG(exception)) {
2987					zend_throw_exception_ex(reflection_exception_ptr, 0,
2988							"Class %s does not exist", Z_STRVAL_P(classname));
2989				}
2990				if (classname == &ztmp) {
2991					zval_ptr_dtor_str(&ztmp);
2992				}
2993				return;
2994			}
2995			break;
2996
2997		case IS_OBJECT:
2998			ce = Z_OBJCE_P(classname);
2999			break;
3000
3001		default:
3002			if (classname == &ztmp) {
3003				zval_ptr_dtor_str(&ztmp);
3004			}
3005			_DO_THROW("The parameter class is expected to be either a string or an object");
3006			/* returns out of this function */
3007	}
3008
3009	if (classname == &ztmp) {
3010		zval_ptr_dtor_str(&ztmp);
3011	}
3012
3013	lcname = zend_str_tolower_dup(name_str, name_len);
3014
3015	if (ce == zend_ce_closure && orig_obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3016		&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3017		&& (mptr = zend_get_closure_invoke_method(Z_OBJ_P(orig_obj))) != NULL)
3018	{
3019		/* do nothing, mptr already set */
3020	} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, name_len)) == NULL) {
3021		efree(lcname);
3022		zend_throw_exception_ex(reflection_exception_ptr, 0,
3023			"Method %s::%s() does not exist", ZSTR_VAL(ce->name), name_str);
3024		return;
3025	}
3026	efree(lcname);
3027
3028	ZVAL_STR_COPY(&name, mptr->common.scope->name);
3029	reflection_update_property_class(object, &name);
3030	ZVAL_STR_COPY(&name, mptr->common.function_name);
3031	reflection_update_property_name(object, &name);
3032	intern->ptr = mptr;
3033	intern->ref_type = REF_TYPE_FUNCTION;
3034	intern->ce = ce;
3035}
3036/* }}} */
3037
3038/* {{{ proto public string ReflectionMethod::__toString()
3039   Returns a string representation */
3040ZEND_METHOD(reflection_method, __toString)
3041{
3042	reflection_object *intern;
3043	zend_function *mptr;
3044	smart_str str = {0};
3045
3046	if (zend_parse_parameters_none() == FAILURE) {
3047		return;
3048	}
3049	GET_REFLECTION_OBJECT_PTR(mptr);
3050	_function_string(&str, mptr, intern->ce, "");
3051	RETURN_STR(smart_str_extract(&str));
3052}
3053/* }}} */
3054
3055/* {{{ proto public mixed ReflectionMethod::getClosure([mixed object])
3056   Invokes the function */
3057ZEND_METHOD(reflection_method, getClosure)
3058{
3059	reflection_object *intern;
3060	zval *obj;
3061	zend_function *mptr;
3062
3063	GET_REFLECTION_OBJECT_PTR(mptr);
3064
3065	if (mptr->common.fn_flags & ZEND_ACC_STATIC)  {
3066		zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
3067	} else {
3068		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) {
3069			return;
3070		}
3071
3072		if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope)) {
3073			_DO_THROW("Given object is not an instance of the class this method was declared in");
3074			/* Returns from this function */
3075		}
3076
3077		/* This is an original closure object and __invoke is to be called. */
3078		if (Z_OBJCE_P(obj) == zend_ce_closure &&
3079			(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
3080		{
3081			ZVAL_COPY(return_value, obj);
3082		} else {
3083			zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj);
3084		}
3085	}
3086}
3087/* }}} */
3088
3089/* {{{ reflection_method_invoke */
3090static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic)
3091{
3092	zval retval;
3093	zval *params = NULL, *val, *object;
3094	reflection_object *intern;
3095	zend_function *mptr;
3096	int i, argc = 0, result;
3097	zend_fcall_info fci;
3098	zend_fcall_info_cache fcc;
3099	zend_class_entry *obj_ce;
3100	zval *param_array;
3101
3102	GET_REFLECTION_OBJECT_PTR(mptr);
3103
3104	if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
3105		zend_throw_exception_ex(reflection_exception_ptr, 0,
3106			"Trying to invoke abstract method %s::%s()",
3107			ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3108		return;
3109	}
3110
3111	if (!(mptr->common.fn_flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) {
3112		zend_throw_exception_ex(reflection_exception_ptr, 0,
3113			"Trying to invoke %s method %s::%s() from scope %s",
3114			mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private",
3115			ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name),
3116			ZSTR_VAL(Z_OBJCE_P(getThis())->name));
3117		return;
3118	}
3119
3120	if (variadic) {
3121		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!*", &object, &params, &argc) == FAILURE) {
3122			return;
3123		}
3124	} else {
3125		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!a", &object, &param_array) == FAILURE) {
3126			return;
3127		}
3128
3129		argc = zend_hash_num_elements(Z_ARRVAL_P(param_array));
3130
3131		params = safe_emalloc(sizeof(zval), argc, 0);
3132		argc = 0;
3133		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(param_array), val) {
3134			ZVAL_COPY(&params[argc], val);
3135			argc++;
3136		} ZEND_HASH_FOREACH_END();
3137	}
3138
3139	/* In case this is a static method, we should'nt pass an object_ptr
3140	 * (which is used as calling context aka $this). We can thus ignore the
3141	 * first parameter.
3142	 *
3143	 * Else, we verify that the given object is an instance of the class.
3144	 */
3145	if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
3146		object = NULL;
3147		obj_ce = mptr->common.scope;
3148	} else {
3149		if (!object) {
3150			zend_throw_exception_ex(reflection_exception_ptr, 0,
3151				"Trying to invoke non static method %s::%s() without an object",
3152				ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3153			return;
3154		}
3155
3156		obj_ce = Z_OBJCE_P(object);
3157
3158		if (!instanceof_function(obj_ce, mptr->common.scope)) {
3159			if (!variadic) {
3160				efree(params);
3161			}
3162			_DO_THROW("Given object is not an instance of the class this method was declared in");
3163			/* Returns from this function */
3164		}
3165	}
3166
3167	fci.size = sizeof(fci);
3168	ZVAL_UNDEF(&fci.function_name);
3169	fci.object = object ? Z_OBJ_P(object) : NULL;
3170	fci.retval = &retval;
3171	fci.param_count = argc;
3172	fci.params = params;
3173	fci.no_separation = 1;
3174
3175	fcc.function_handler = mptr;
3176	fcc.called_scope = intern->ce;
3177	fcc.object = object ? Z_OBJ_P(object) : NULL;
3178
3179	/*
3180	 * Copy the zend_function when calling via handler (e.g. Closure::__invoke())
3181	 */
3182	if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
3183		fcc.function_handler = _copy_function(mptr);
3184	}
3185
3186	result = zend_call_function(&fci, &fcc);
3187
3188	if (!variadic) {
3189		for (i = 0; i < argc; i++) {
3190			zval_ptr_dtor(&params[i]);
3191		}
3192		efree(params);
3193	}
3194
3195	if (result == FAILURE) {
3196		zend_throw_exception_ex(reflection_exception_ptr, 0,
3197			"Invocation of method %s::%s() failed", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3198		return;
3199	}
3200
3201	if (Z_TYPE(retval) != IS_UNDEF) {
3202		if (Z_ISREF(retval)) {
3203			zend_unwrap_reference(&retval);
3204		}
3205		ZVAL_COPY_VALUE(return_value, &retval);
3206	}
3207}
3208/* }}} */
3209
3210/* {{{ proto public mixed ReflectionMethod::invoke(mixed object, mixed* args)
3211   Invokes the method. */
3212ZEND_METHOD(reflection_method, invoke)
3213{
3214	reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3215}
3216/* }}} */
3217
3218/* {{{ proto public mixed ReflectionMethod::invokeArgs(mixed object, array args)
3219   Invokes the function and pass its arguments as array. */
3220ZEND_METHOD(reflection_method, invokeArgs)
3221{
3222	reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3223}
3224/* }}} */
3225
3226/* {{{ proto public bool ReflectionMethod::isFinal()
3227   Returns whether this method is final */
3228ZEND_METHOD(reflection_method, isFinal)
3229{
3230	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3231}
3232/* }}} */
3233
3234/* {{{ proto public bool ReflectionMethod::isAbstract()
3235   Returns whether this method is abstract */
3236ZEND_METHOD(reflection_method, isAbstract)
3237{
3238	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ABSTRACT);
3239}
3240/* }}} */
3241
3242/* {{{ proto public bool ReflectionMethod::isPublic()
3243   Returns whether this method is public */
3244ZEND_METHOD(reflection_method, isPublic)
3245{
3246	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3247}
3248/* }}} */
3249
3250/* {{{ proto public bool ReflectionMethod::isPrivate()
3251   Returns whether this method is private */
3252ZEND_METHOD(reflection_method, isPrivate)
3253{
3254	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3255}
3256/* }}} */
3257
3258/* {{{ proto public bool ReflectionMethod::isProtected()
3259   Returns whether this method is protected */
3260ZEND_METHOD(reflection_method, isProtected)
3261{
3262	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3263}
3264/* }}} */
3265
3266/* {{{ proto public bool ReflectionMethod::isStatic()
3267   Returns whether this method is static */
3268ZEND_METHOD(reflection_method, isStatic)
3269{
3270	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
3271}
3272/* }}} */
3273
3274/* {{{ proto public bool ReflectionFunction::isDeprecated()
3275   Returns whether this function is deprecated */
3276ZEND_METHOD(reflection_function, isDeprecated)
3277{
3278	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_DEPRECATED);
3279}
3280/* }}} */
3281
3282/* {{{ proto public bool ReflectionFunction::isGenerator()
3283   Returns whether this function is a generator */
3284ZEND_METHOD(reflection_function, isGenerator)
3285{
3286	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_GENERATOR);
3287}
3288/* }}} */
3289
3290/* {{{ proto public bool ReflectionFunction::isVariadic()
3291   Returns whether this function is variadic */
3292ZEND_METHOD(reflection_function, isVariadic)
3293{
3294	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VARIADIC);
3295}
3296/* }}} */
3297
3298/* {{{ proto public bool ReflectionFunction::inNamespace()
3299   Returns whether this function is defined in namespace */
3300ZEND_METHOD(reflection_function, inNamespace)
3301{
3302	zval *name;
3303	const char *backslash;
3304
3305	if (zend_parse_parameters_none() == FAILURE) {
3306		return;
3307	}
3308	if ((name = _default_load_name(getThis())) == NULL) {
3309		RETURN_FALSE;
3310	}
3311	if (Z_TYPE_P(name) == IS_STRING
3312		&& (backslash = zend_memrchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name)))
3313		&& backslash > Z_STRVAL_P(name))
3314	{
3315		RETURN_TRUE;
3316	}
3317	RETURN_FALSE;
3318}
3319/* }}} */
3320
3321/* {{{ proto public string ReflectionFunction::getNamespaceName()
3322   Returns the name of namespace where this function is defined */
3323ZEND_METHOD(reflection_function, getNamespaceName)
3324{
3325	zval *name;
3326	const char *backslash;
3327
3328	if (zend_parse_parameters_none() == FAILURE) {
3329		return;
3330	}
3331	if ((name = _default_load_name(getThis())) == NULL) {
3332		RETURN_FALSE;
3333	}
3334	if (Z_TYPE_P(name) == IS_STRING
3335		&& (backslash = zend_memrchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name)))
3336		&& backslash > Z_STRVAL_P(name))
3337	{
3338		RETURN_STRINGL(Z_STRVAL_P(name), backslash - Z_STRVAL_P(name));
3339	}
3340	RETURN_EMPTY_STRING();
3341}
3342/* }}} */
3343
3344/* {{{ proto public string ReflectionFunction::getShortName()
3345   Returns the short name of the function (without namespace part) */
3346ZEND_METHOD(reflection_function, getShortName)
3347{
3348	zval *name;
3349	const char *backslash;
3350
3351	if (zend_parse_parameters_none() == FAILURE) {
3352		return;
3353	}
3354	if ((name = _default_load_name(getThis())) == NULL) {
3355		RETURN_FALSE;
3356	}
3357	if (Z_TYPE_P(name) == IS_STRING
3358		&& (backslash = zend_memrchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name)))
3359		&& backslash > Z_STRVAL_P(name))
3360	{
3361		RETURN_STRINGL(backslash + 1, Z_STRLEN_P(name) - (backslash - Z_STRVAL_P(name) + 1));
3362	}
3363	ZVAL_COPY_DEREF(return_value, name);
3364}
3365/* }}} */
3366
3367/* {{{ proto public bool ReflectionFunctionAbstract:hasReturnType()
3368   Return whether the function has a return type */
3369ZEND_METHOD(reflection_function, hasReturnType)
3370{
3371	reflection_object *intern;
3372	zend_function *fptr;
3373
3374	if (zend_parse_parameters_none() == FAILURE) {
3375		return;
3376	}
3377
3378	GET_REFLECTION_OBJECT_PTR(fptr);
3379
3380	RETVAL_BOOL(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE);
3381}
3382/* }}} */
3383
3384/* {{{ proto public string ReflectionFunctionAbstract::getReturnType()
3385   Returns the return type associated with the function */
3386ZEND_METHOD(reflection_function, getReturnType)
3387{
3388	reflection_object *intern;
3389	zend_function *fptr;
3390
3391	if (zend_parse_parameters_none() == FAILURE) {
3392		return;
3393	}
3394
3395	GET_REFLECTION_OBJECT_PTR(fptr);
3396
3397	if (!(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
3398		RETURN_NULL();
3399	}
3400
3401	reflection_type_factory(_copy_function(fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, &fptr->common.arg_info[-1], return_value);
3402}
3403/* }}} */
3404
3405/* {{{ proto public bool ReflectionMethod::isConstructor()
3406   Returns whether this method is the constructor */
3407ZEND_METHOD(reflection_method, isConstructor)
3408{
3409	reflection_object *intern;
3410	zend_function *mptr;
3411
3412	if (zend_parse_parameters_none() == FAILURE) {
3413		return;
3414	}
3415	GET_REFLECTION_OBJECT_PTR(mptr);
3416	/* we need to check if the ctor is the ctor of the class level we we
3417	 * looking at since we might be looking at an inherited old style ctor
3418	 * defined in base class. */
3419	RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_CTOR && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope);
3420}
3421/* }}} */
3422
3423/* {{{ proto public bool ReflectionMethod::isDestructor()
3424   Returns whether this method is static */
3425ZEND_METHOD(reflection_method, isDestructor)
3426{
3427	reflection_object *intern;
3428	zend_function *mptr;
3429
3430	if (zend_parse_parameters_none() == FAILURE) {
3431		return;
3432	}
3433	GET_REFLECTION_OBJECT_PTR(mptr);
3434	RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_DTOR);
3435}
3436/* }}} */
3437
3438/* {{{ proto public int ReflectionMethod::getModifiers()
3439   Returns a bitfield of the access modifiers for this method */
3440ZEND_METHOD(reflection_method, getModifiers)
3441{
3442	reflection_object *intern;
3443	zend_function *mptr;
3444	uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_IMPLICIT_PUBLIC
3445		| ZEND_ACC_STATIC | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL;
3446
3447	if (zend_parse_parameters_none() == FAILURE) {
3448		return;
3449	}
3450	GET_REFLECTION_OBJECT_PTR(mptr);
3451
3452	RETURN_LONG((mptr->common.fn_flags & keep_flags));
3453}
3454/* }}} */
3455
3456/* {{{ proto public ReflectionClass ReflectionMethod::getDeclaringClass()
3457   Get the declaring class */
3458ZEND_METHOD(reflection_method, getDeclaringClass)
3459{
3460	reflection_object *intern;
3461	zend_function *mptr;
3462
3463	GET_REFLECTION_OBJECT_PTR(mptr);
3464
3465	if (zend_parse_parameters_none() == FAILURE) {
3466		return;
3467	}
3468
3469	zend_reflection_class_factory(mptr->common.scope, return_value);
3470}
3471/* }}} */
3472
3473/* {{{ proto public ReflectionClass ReflectionMethod::getPrototype()
3474   Get the prototype */
3475ZEND_METHOD(reflection_method, getPrototype)
3476{
3477	reflection_object *intern;
3478	zend_function *mptr;
3479
3480	GET_REFLECTION_OBJECT_PTR(mptr);
3481
3482	if (zend_parse_parameters_none() == FAILURE) {
3483		return;
3484	}
3485
3486	if (!mptr->common.prototype) {
3487		zend_throw_exception_ex(reflection_exception_ptr, 0,
3488			"Method %s::%s does not have a prototype", ZSTR_VAL(intern->ce->name), ZSTR_VAL(mptr->common.function_name));
3489		return;
3490	}
3491
3492	reflection_method_factory(mptr->common.prototype->common.scope, mptr->common.prototype, NULL, return_value);
3493}
3494/* }}} */
3495
3496/* {{{ proto public void ReflectionMethod::setAccessible(bool visible)
3497   Sets whether non-public methods can be invoked */
3498ZEND_METHOD(reflection_method, setAccessible)
3499{
3500	reflection_object *intern;
3501	zend_bool visible;
3502
3503	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
3504		return;
3505	}
3506
3507	intern = Z_REFLECTION_P(getThis());
3508
3509	intern->ignore_visibility = visible;
3510}
3511/* }}} */
3512
3513/* {{{ proto public void ReflectionClassConstant::__construct(mixed class, string name)
3514   Constructor. Throws an Exception in case the given class constant does not exist */
3515ZEND_METHOD(reflection_class_constant, __construct)
3516{
3517	zval *classname, *object, name, cname;
3518	zend_string *constname;
3519	reflection_object *intern;
3520	zend_class_entry *ce;
3521	zend_class_constant *constant = NULL;
3522
3523	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zS", &classname, &constname) == FAILURE) {
3524		return;
3525	}
3526
3527	object = getThis();
3528	intern = Z_REFLECTION_P(object);
3529
3530	/* Find the class entry */
3531	switch (Z_TYPE_P(classname)) {
3532		case IS_STRING:
3533			if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
3534				zend_throw_exception_ex(reflection_exception_ptr, 0,
3535						"Class %s does not exist", Z_STRVAL_P(classname));
3536				return;
3537			}
3538			break;
3539
3540		case IS_OBJECT:
3541			ce = Z_OBJCE_P(classname);
3542			break;
3543
3544		default:
3545			_DO_THROW("The parameter class is expected to be either a string or an object");
3546			/* returns out of this function */
3547	}
3548
3549	if ((constant = zend_hash_find_ptr(&ce->constants_table, constname)) == NULL) {
3550		zend_throw_exception_ex(reflection_exception_ptr, 0, "Class Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
3551		return;
3552	}
3553
3554	ZVAL_STR_COPY(&name, constname);
3555	ZVAL_STR_COPY(&cname, ce->name);
3556
3557	intern->ptr = constant;
3558	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
3559	intern->ce = constant->ce;
3560	intern->ignore_visibility = 0;
3561	reflection_update_property_name(object, &name);
3562	reflection_update_property_class(object, &cname);
3563}
3564/* }}} */
3565
3566/* {{{ proto public string ReflectionClassConstant::__toString()
3567   Returns a string representation */
3568ZEND_METHOD(reflection_class_constant, __toString)
3569{
3570	reflection_object *intern;
3571	zend_class_constant *ref;
3572	smart_str str = {0};
3573	zval name;
3574
3575	if (zend_parse_parameters_none() == FAILURE) {
3576		return;
3577	}
3578	GET_REFLECTION_OBJECT_PTR(ref);
3579	_default_get_name(getThis(), &name);
3580	_class_const_string(&str, Z_STRVAL(name), ref, "");
3581	zval_ptr_dtor(&name);
3582	RETURN_STR(smart_str_extract(&str));
3583}
3584/* }}} */
3585
3586/* {{{ proto public string ReflectionClassConstant::getName()
3587   Returns the constant' name */
3588ZEND_METHOD(reflection_class_constant, getName)
3589{
3590	if (zend_parse_parameters_none() == FAILURE) {
3591		return;
3592	}
3593	_default_get_name(getThis(), return_value);
3594}
3595/* }}} */
3596
3597static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
3598{
3599	reflection_object *intern;
3600	zend_class_constant *ref;
3601
3602	if (zend_parse_parameters_none() == FAILURE) {
3603		return;
3604	}
3605	GET_REFLECTION_OBJECT_PTR(ref);
3606	RETURN_BOOL(Z_ACCESS_FLAGS(ref->value) & mask);
3607}
3608/* }}} */
3609
3610/* {{{ proto public bool ReflectionClassConstant::isPublic()
3611   Returns whether this constant is public */
3612ZEND_METHOD(reflection_class_constant, isPublic)
3613{
3614	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC);
3615}
3616/* }}} */
3617
3618/* {{{ proto public bool ReflectionClassConstant::isPrivate()
3619   Returns whether this constant is private */
3620ZEND_METHOD(reflection_class_constant, isPrivate)
3621{
3622	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3623}
3624/* }}} */
3625
3626/* {{{ proto public bool ReflectionClassConstant::isProtected()
3627   Returns whether this constant is protected */
3628ZEND_METHOD(reflection_class_constant, isProtected)
3629{
3630	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3631}
3632/* }}} */
3633
3634/* {{{ proto public int ReflectionClassConstant::getModifiers()
3635   Returns a bitfield of the access modifiers for this constant */
3636ZEND_METHOD(reflection_class_constant, getModifiers)
3637{
3638	reflection_object *intern;
3639	zend_class_constant *ref;
3640
3641	if (zend_parse_parameters_none() == FAILURE) {
3642		return;
3643	}
3644	GET_REFLECTION_OBJECT_PTR(ref);
3645
3646	RETURN_LONG(Z_ACCESS_FLAGS(ref->value));
3647}
3648/* }}} */
3649
3650/* {{{ proto public mixed ReflectionClassConstant::getValue()
3651   Returns this constant's value */
3652ZEND_METHOD(reflection_class_constant, getValue)
3653{
3654	reflection_object *intern;
3655	zend_class_constant *ref;
3656
3657	if (zend_parse_parameters_none() == FAILURE) {
3658		return;
3659	}
3660	GET_REFLECTION_OBJECT_PTR(ref);
3661
3662	ZVAL_COPY_OR_DUP(return_value, &ref->value);
3663	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
3664		zval_update_constant_ex(return_value, ref->ce);
3665	}
3666}
3667/* }}} */
3668
3669/* {{{ proto public ReflectionClass ReflectionClassConstant::getDeclaringClass()
3670   Get the declaring class */
3671ZEND_METHOD(reflection_class_constant, getDeclaringClass)
3672{
3673	reflection_object *intern;
3674	zend_class_constant *ref;
3675
3676	if (zend_parse_parameters_none() == FAILURE) {
3677		return;
3678	}
3679	GET_REFLECTION_OBJECT_PTR(ref);
3680
3681	zend_reflection_class_factory(ref->ce, return_value);
3682}
3683/* }}} */
3684
3685/* {{{ proto public string ReflectionClassConstant::getDocComment()
3686   Returns the doc comment for this constant */
3687ZEND_METHOD(reflection_class_constant, getDocComment)
3688{
3689	reflection_object *intern;
3690	zend_class_constant *ref;
3691
3692	if (zend_parse_parameters_none() == FAILURE) {
3693		return;
3694	}
3695	GET_REFLECTION_OBJECT_PTR(ref);
3696	if (ref->doc_comment) {
3697		RETURN_STR_COPY(ref->doc_comment);
3698	}
3699	RETURN_FALSE;
3700}
3701/* }}} */
3702
3703/* {{{ proto public static mixed ReflectionClass::export(mixed argument [, bool return]) throws ReflectionException
3704   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
3705ZEND_METHOD(reflection_class, export)
3706{
3707	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_class_ptr, 1);
3708}
3709/* }}} */
3710
3711/* {{{ reflection_class_object_ctor */
3712static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_object)
3713{
3714	zval *argument;
3715	zval *object;
3716	zval classname;
3717	reflection_object *intern;
3718	zend_class_entry *ce;
3719
3720	if (is_object) {
3721		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &argument) == FAILURE) {
3722			return;
3723		}
3724	} else {
3725		if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &argument) == FAILURE) {
3726			return;
3727		}
3728	}
3729
3730	object = getThis();
3731	intern = Z_REFLECTION_P(object);
3732
3733	if (Z_TYPE_P(argument) == IS_OBJECT) {
3734		ZVAL_STR_COPY(&classname, Z_OBJCE_P(argument)->name);
3735		reflection_update_property_name(object, &classname);
3736		intern->ptr = Z_OBJCE_P(argument);
3737		if (is_object) {
3738			ZVAL_COPY(&intern->obj, argument);
3739		}
3740	} else {
3741		convert_to_string_ex(argument);
3742		if ((ce = zend_lookup_class(Z_STR_P(argument))) == NULL) {
3743			if (!EG(exception)) {
3744				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class %s does not exist", Z_STRVAL_P(argument));
3745			}
3746			return;
3747		}
3748
3749		ZVAL_STR_COPY(&classname, ce->name);
3750		reflection_update_property_name(object, &classname);
3751
3752		intern->ptr = ce;
3753	}
3754	intern->ref_type = REF_TYPE_OTHER;
3755}
3756/* }}} */
3757
3758/* {{{ proto public void ReflectionClass::__construct(mixed argument) throws ReflectionException
3759   Constructor. Takes a string or an instance as an argument */
3760ZEND_METHOD(reflection_class, __construct)
3761{
3762	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3763}
3764/* }}} */
3765
3766/* {{{ add_class_vars */
3767static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value)
3768{
3769	zend_property_info *prop_info;
3770	zval *prop, prop_copy;
3771	zend_string *key;
3772
3773	ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
3774		if (((prop_info->flags & ZEND_ACC_SHADOW) &&
3775		     prop_info->ce != ce) ||
3776		    ((prop_info->flags & ZEND_ACC_PROTECTED) &&
3777		     !zend_check_protected(prop_info->ce, ce)) ||
3778		    ((prop_info->flags & ZEND_ACC_PRIVATE) &&
3779		     prop_info->ce != ce)) {
3780			continue;
3781		}
3782		prop = NULL;
3783		if (statics && (prop_info->flags & ZEND_ACC_STATIC) != 0) {
3784			prop = &ce->default_static_members_table[prop_info->offset];
3785			ZVAL_DEINDIRECT(prop);
3786		} else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) {
3787			prop = &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
3788		}
3789		if (!prop) {
3790			continue;
3791		}
3792
3793		/* copy: enforce read only access */
3794		ZVAL_DEREF(prop);
3795		ZVAL_COPY_OR_DUP(&prop_copy, prop);
3796
3797		/* this is necessary to make it able to work with default array
3798		* properties, returned to user */
3799		if (Z_TYPE(prop_copy) == IS_CONSTANT_AST) {
3800			if (UNEXPECTED(zval_update_constant_ex(&prop_copy, NULL) != SUCCESS)) {
3801				return;
3802			}
3803		}
3804
3805		zend_hash_update(Z_ARRVAL_P(return_value), key, &prop_copy);
3806	} ZEND_HASH_FOREACH_END();
3807}
3808/* }}} */
3809
3810/* {{{ proto public array ReflectionClass::getStaticProperties()
3811   Returns an associative array containing all static property values of the class */
3812ZEND_METHOD(reflection_class, getStaticProperties)
3813{
3814	reflection_object *intern;
3815	zend_class_entry *ce;
3816
3817	if (zend_parse_parameters_none() == FAILURE) {
3818		return;
3819	}
3820
3821	GET_REFLECTION_OBJECT_PTR(ce);
3822
3823	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
3824		return;
3825	}
3826
3827	array_init(return_value);
3828	add_class_vars(ce, 1, return_value);
3829}
3830/* }}} */
3831
3832/* {{{ proto public mixed ReflectionClass::getStaticPropertyValue(string name [, mixed default])
3833   Returns the value of a static property */
3834ZEND_METHOD(reflection_class, getStaticPropertyValue)
3835{
3836	reflection_object *intern;
3837	zend_class_entry *ce;
3838	zend_string *name;
3839	zval *prop, *def_value = NULL;
3840
3841	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &name, &def_value) == FAILURE) {
3842		return;
3843	}
3844
3845	GET_REFLECTION_OBJECT_PTR(ce);
3846
3847	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
3848		return;
3849	}
3850	prop = zend_std_get_static_property(ce, name, 1);
3851	if (!prop) {
3852		if (def_value) {
3853			ZVAL_COPY(return_value, def_value);
3854		} else {
3855			zend_throw_exception_ex(reflection_exception_ptr, 0,
3856				"Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
3857		}
3858		return;
3859	} else {
3860		ZVAL_COPY_DEREF(return_value, prop);
3861	}
3862}
3863/* }}} */
3864
3865/* {{{ proto public void ReflectionClass::setStaticPropertyValue(string $name, mixed $value)
3866   Sets the value of a static property */
3867ZEND_METHOD(reflection_class, setStaticPropertyValue)
3868{
3869	reflection_object *intern;
3870	zend_class_entry *ce;
3871	zend_string *name;
3872	zval *variable_ptr, *value;
3873
3874	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &name, &value) == FAILURE) {
3875		return;
3876	}
3877
3878	GET_REFLECTION_OBJECT_PTR(ce);
3879
3880	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
3881		return;
3882	}
3883	variable_ptr = zend_std_get_static_property(ce, name, 1);
3884	if (!variable_ptr) {
3885		zend_throw_exception_ex(reflection_exception_ptr, 0,
3886				"Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
3887		return;
3888	}
3889	ZVAL_DEREF(variable_ptr);
3890	zval_ptr_dtor(variable_ptr);
3891	ZVAL_COPY(variable_ptr, value);
3892}
3893/* }}} */
3894
3895/* {{{ proto public array ReflectionClass::getDefaultProperties()
3896   Returns an associative array containing copies of all default property values of the class */
3897ZEND_METHOD(reflection_class, getDefaultProperties)
3898{
3899	reflection_object *intern;
3900	zend_class_entry *ce;
3901
3902	if (zend_parse_parameters_none() == FAILURE) {
3903		return;
3904	}
3905	GET_REFLECTION_OBJECT_PTR(ce);
3906	array_init(return_value);
3907	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
3908		return;
3909	}
3910	add_class_vars(ce, 1, return_value);
3911	add_class_vars(ce, 0, return_value);
3912}
3913/* }}} */
3914
3915/* {{{ proto public string ReflectionClass::__toString()
3916   Returns a string representation */
3917ZEND_METHOD(reflection_class, __toString)
3918{
3919	reflection_object *intern;
3920	zend_class_entry *ce;
3921	smart_str str = {0};
3922
3923	if (zend_parse_parameters_none() == FAILURE) {
3924		return;
3925	}
3926	GET_REFLECTION_OBJECT_PTR(ce);
3927	_class_string(&str, ce, &intern->obj, "");
3928	RETURN_STR(smart_str_extract(&str));
3929}
3930/* }}} */
3931
3932/* {{{ proto public string ReflectionClass::getName()
3933   Returns the class' name */
3934ZEND_METHOD(reflection_class, getName)
3935{
3936	if (zend_parse_parameters_none() == FAILURE) {
3937		return;
3938	}
3939	_default_get_name(getThis(), return_value);
3940}
3941/* }}} */
3942
3943/* {{{ proto public bool ReflectionClass::isInternal()
3944   Returns whether this class is an internal class */
3945ZEND_METHOD(reflection_class, isInternal)
3946{
3947	reflection_object *intern;
3948	zend_class_entry *ce;
3949
3950	if (zend_parse_parameters_none() == FAILURE) {
3951		return;
3952	}
3953	GET_REFLECTION_OBJECT_PTR(ce);
3954	RETURN_BOOL(ce->type == ZEND_INTERNAL_CLASS);
3955}
3956/* }}} */
3957
3958/* {{{ proto public bool ReflectionClass::isUserDefined()
3959   Returns whether this class is user-defined */
3960ZEND_METHOD(reflection_class, isUserDefined)
3961{
3962	reflection_object *intern;
3963	zend_class_entry *ce;
3964
3965	if (zend_parse_parameters_none() == FAILURE) {
3966		return;
3967	}
3968	GET_REFLECTION_OBJECT_PTR(ce);
3969	RETURN_BOOL(ce->type == ZEND_USER_CLASS);
3970}
3971/* }}} */
3972
3973/* {{{ proto public bool ReflectionClass::isAnonymous()
3974   Returns whether this class is anonymous */
3975ZEND_METHOD(reflection_class, isAnonymous)
3976{
3977	reflection_object *intern;
3978	zend_class_entry *ce;
3979
3980	if (zend_parse_parameters_none() == FAILURE) {
3981		return;
3982	}
3983	GET_REFLECTION_OBJECT_PTR(ce);
3984	RETURN_BOOL(ce->ce_flags & ZEND_ACC_ANON_CLASS);
3985}
3986/* }}} */
3987
3988/* {{{ proto public string ReflectionClass::getFileName()
3989   Returns the filename of the file this class was declared in */
3990ZEND_METHOD(reflection_class, getFileName)
3991{
3992	reflection_object *intern;
3993	zend_class_entry *ce;
3994
3995	if (zend_parse_parameters_none() == FAILURE) {
3996		return;
3997	}
3998	GET_REFLECTION_OBJECT_PTR(ce);
3999	if (ce->type == ZEND_USER_CLASS) {
4000		RETURN_STR_COPY(ce->info.user.filename);
4001	}
4002	RETURN_FALSE;
4003}
4004/* }}} */
4005
4006/* {{{ proto public int ReflectionClass::getStartLine()
4007   Returns the line this class' declaration starts at */
4008ZEND_METHOD(reflection_class, getStartLine)
4009{
4010	reflection_object *intern;
4011	zend_class_entry *ce;
4012
4013	if (zend_parse_parameters_none() == FAILURE) {
4014		return;
4015	}
4016	GET_REFLECTION_OBJECT_PTR(ce);
4017	if (ce->type == ZEND_USER_CLASS) {
4018		RETURN_LONG(ce->info.user.line_start);
4019	}
4020	RETURN_FALSE;
4021}
4022/* }}} */
4023
4024/* {{{ proto public int ReflectionClass::getEndLine()
4025   Returns the line this class' declaration ends at */
4026ZEND_METHOD(reflection_class, getEndLine)
4027{
4028	reflection_object *intern;
4029	zend_class_entry *ce;
4030
4031	if (zend_parse_parameters_none() == FAILURE) {
4032		return;
4033	}
4034	GET_REFLECTION_OBJECT_PTR(ce);
4035	if (ce->type == ZEND_USER_CLASS) {
4036		RETURN_LONG(ce->info.user.line_end);
4037	}
4038	RETURN_FALSE;
4039}
4040/* }}} */
4041
4042/* {{{ proto public string ReflectionClass::getDocComment()
4043   Returns the doc comment for this class */
4044ZEND_METHOD(reflection_class, getDocComment)
4045{
4046	reflection_object *intern;
4047	zend_class_entry *ce;
4048
4049	if (zend_parse_parameters_none() == FAILURE) {
4050		return;
4051	}
4052	GET_REFLECTION_OBJECT_PTR(ce);
4053	if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) {
4054		RETURN_STR_COPY(ce->info.user.doc_comment);
4055	}
4056	RETURN_FALSE;
4057}
4058/* }}} */
4059
4060/* {{{ proto public ReflectionMethod ReflectionClass::getConstructor()
4061   Returns the class' constructor if there is one, NULL otherwise */
4062ZEND_METHOD(reflection_class, getConstructor)
4063{
4064	reflection_object *intern;
4065	zend_class_entry *ce;
4066
4067	if (zend_parse_parameters_none() == FAILURE) {
4068		return;
4069	}
4070	GET_REFLECTION_OBJECT_PTR(ce);
4071
4072	if (ce->constructor) {
4073		reflection_method_factory(ce, ce->constructor, NULL, return_value);
4074	} else {
4075		RETURN_NULL();
4076	}
4077}
4078/* }}} */
4079
4080/* {{{ proto public bool ReflectionClass::hasMethod(string name)
4081   Returns whether a method exists or not */
4082ZEND_METHOD(reflection_class, hasMethod)
4083{
4084	reflection_object *intern;
4085	zend_class_entry *ce;
4086	char *name, *lc_name;
4087	size_t name_len;
4088
4089	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
4090		return;
4091	}
4092
4093	GET_REFLECTION_OBJECT_PTR(ce);
4094	lc_name = zend_str_tolower_dup(name, name_len);
4095	if ((ce == zend_ce_closure && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
4096		&& memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0)
4097		|| zend_hash_str_exists(&ce->function_table, lc_name, name_len)) {
4098		efree(lc_name);
4099		RETURN_TRUE;
4100	} else {
4101		efree(lc_name);
4102		RETURN_FALSE;
4103	}
4104}
4105/* }}} */
4106
4107/* {{{ proto public ReflectionMethod ReflectionClass::getMethod(string name) throws ReflectionException
4108   Returns the class' method specified by its name */
4109ZEND_METHOD(reflection_class, getMethod)
4110{
4111	reflection_object *intern;
4112	zend_class_entry *ce;
4113	zend_function *mptr;
4114	zval obj_tmp;
4115	char *name, *lc_name;
4116	size_t name_len;
4117
4118	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &name_len) == FAILURE) {
4119		return;
4120	}
4121
4122	GET_REFLECTION_OBJECT_PTR(ce);
4123	lc_name = zend_str_tolower_dup(name, name_len);
4124	if (ce == zend_ce_closure && !Z_ISUNDEF(intern->obj) && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
4125		&& memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
4126		&& (mptr = zend_get_closure_invoke_method(Z_OBJ(intern->obj))) != NULL)
4127	{
4128		/* don't assign closure_object since we only reflect the invoke handler
4129		   method and not the closure definition itself */
4130		reflection_method_factory(ce, mptr, NULL, return_value);
4131		efree(lc_name);
4132	} else if (ce == zend_ce_closure && Z_ISUNDEF(intern->obj) && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
4133		&& memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
4134		&& object_init_ex(&obj_tmp, ce) == SUCCESS && (mptr = zend_get_closure_invoke_method(Z_OBJ(obj_tmp))) != NULL) {
4135		/* don't assign closure_object since we only reflect the invoke handler
4136		   method and not the closure definition itself */
4137		reflection_method_factory(ce, mptr, NULL, return_value);
4138		zval_ptr_dtor(&obj_tmp);
4139		efree(lc_name);
4140	} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lc_name, name_len)) != NULL) {
4141		reflection_method_factory(ce, mptr, NULL, return_value);
4142		efree(lc_name);
4143	} else {
4144		efree(lc_name);
4145		zend_throw_exception_ex(reflection_exception_ptr, 0,
4146				"Method %s does not exist", name);
4147		return;
4148	}
4149}
4150/* }}} */
4151
4152/* {{{ _addmethod */
4153static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, zend_long filter)
4154{
4155	if (mptr->common.fn_flags & filter) {
4156		zval method;
4157		reflection_method_factory(ce, mptr, NULL, &method);
4158		add_next_index_zval(retval, &method);
4159	}
4160}
4161/* }}} */
4162
4163/* {{{ _addmethod */
4164static int _addmethod_va(zval *el, int num_args, va_list args, zend_hash_key *hash_key)
4165{
4166	zend_function *mptr = (zend_function*)Z_PTR_P(el);
4167	zend_class_entry *ce = *va_arg(args, zend_class_entry**);
4168	zval *retval = va_arg(args, zval*);
4169	long filter = va_arg(args, long);
4170
4171	_addmethod(mptr, ce, retval, filter);
4172	return ZEND_HASH_APPLY_KEEP;
4173}
4174/* }}} */
4175
4176/* {{{ proto public ReflectionMethod[] ReflectionClass::getMethods([long $filter])
4177   Returns an array of this class' methods */
4178ZEND_METHOD(reflection_class, getMethods)
4179{
4180	reflection_object *intern;
4181	zend_class_entry *ce;
4182	zend_long filter = 0;
4183	zend_bool filter_is_null = 1;
4184
4185	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4186		return;
4187	}
4188
4189	if (filter_is_null) {
4190		filter = ZEND_ACC_PPP_MASK | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL | ZEND_ACC_STATIC;
4191	}
4192
4193	GET_REFLECTION_OBJECT_PTR(ce);
4194
4195	array_init(return_value);
4196	zend_hash_apply_with_arguments(&ce->function_table, (apply_func_args_t) _addmethod_va, 4, &ce, return_value, filter);
4197
4198	if (instanceof_function(ce, zend_ce_closure)) {
4199		zend_bool has_obj = Z_TYPE(intern->obj) != IS_UNDEF;
4200		zval obj_tmp;
4201		zend_object *obj;
4202		if (!has_obj) {
4203			object_init_ex(&obj_tmp, ce);
4204			obj = Z_OBJ(obj_tmp);
4205		} else {
4206			obj = Z_OBJ(intern->obj);
4207		}
4208		zend_function *closure = zend_get_closure_invoke_method(obj);
4209		if (closure) {
4210			_addmethod(closure, ce, return_value, filter);
4211		}
4212		if (!has_obj) {
4213			zval_ptr_dtor(&obj_tmp);
4214		}
4215	}
4216}
4217/* }}} */
4218
4219/* {{{ proto public bool ReflectionClass::hasProperty(string name)
4220   Returns whether a property exists or not */
4221ZEND_METHOD(reflection_class, hasProperty)
4222{
4223	reflection_object *intern;
4224	zend_property_info *property_info;
4225	zend_class_entry *ce;
4226	zend_string *name;
4227	zval property;
4228
4229	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4230		return;
4231	}
4232
4233	GET_REFLECTION_OBJECT_PTR(ce);
4234	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
4235		if (property_info->flags & ZEND_ACC_SHADOW) {
4236			RETURN_FALSE;
4237		}
4238		RETURN_TRUE;
4239	} else {
4240		if (Z_TYPE(intern->obj) != IS_UNDEF && Z_OBJ_HANDLER(intern->obj, has_property)) {
4241			ZVAL_STR_COPY(&property, name);
4242			if (Z_OBJ_HANDLER(intern->obj, has_property)(&intern->obj, &property, 2, NULL)) {
4243				zval_ptr_dtor(&property);
4244				RETURN_TRUE;
4245			}
4246			zval_ptr_dtor(&property);
4247		}
4248		RETURN_FALSE;
4249	}
4250}
4251/* }}} */
4252
4253/* {{{ proto public ReflectionProperty ReflectionClass::getProperty(string name) throws ReflectionException
4254   Returns the class' property specified by its name */
4255ZEND_METHOD(reflection_class, getProperty)
4256{
4257	reflection_object *intern;
4258	zend_class_entry *ce, *ce2;
4259	zend_property_info *property_info;
4260	zend_string *name, *classname;
4261	char *tmp, *str_name;
4262	size_t classname_len, str_name_len;
4263
4264	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4265		return;
4266	}
4267
4268	GET_REFLECTION_OBJECT_PTR(ce);
4269	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
4270		if ((property_info->flags & ZEND_ACC_SHADOW) == 0) {
4271			reflection_property_factory(ce, name, property_info, return_value);
4272			return;
4273		}
4274	} else if (Z_TYPE(intern->obj) != IS_UNDEF) {
4275		/* Check for dynamic properties */
4276		if (zend_hash_exists(Z_OBJ_HT(intern->obj)->get_properties(&intern->obj), name)) {
4277			zend_property_info property_info_tmp;
4278			property_info_tmp.flags = ZEND_ACC_IMPLICIT_PUBLIC;
4279			property_info_tmp.name = name;
4280			property_info_tmp.doc_comment = NULL;
4281			property_info_tmp.ce = ce;
4282
4283			reflection_property_factory(ce, name, &property_info_tmp, return_value);
4284			return;
4285		}
4286	}
4287	str_name = ZSTR_VAL(name);
4288	if ((tmp = strstr(ZSTR_VAL(name), "::")) != NULL) {
4289		classname_len = tmp - ZSTR_VAL(name);
4290		classname = zend_string_alloc(classname_len, 0);
4291		zend_str_tolower_copy(ZSTR_VAL(classname), ZSTR_VAL(name), classname_len);
4292		ZSTR_VAL(classname)[classname_len] = '\0';
4293		str_name_len = ZSTR_LEN(name) - (classname_len + 2);
4294		str_name = tmp + 2;
4295
4296		ce2 = zend_lookup_class(classname);
4297		if (!ce2) {
4298			if (!EG(exception)) {
4299				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class %s does not exist", ZSTR_VAL(classname));
4300			}
4301			zend_string_release_ex(classname, 0);
4302			return;
4303		}
4304		zend_string_release_ex(classname, 0);
4305
4306		if (!instanceof_function(ce, ce2)) {
4307			zend_throw_exception_ex(reflection_exception_ptr, -1, "Fully qualified property name %s::%s does not specify a base class of %s", ZSTR_VAL(ce2->name), str_name, ZSTR_VAL(ce->name));
4308			return;
4309		}
4310		ce = ce2;
4311
4312		if ((property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len)) != NULL && (property_info->flags & ZEND_ACC_SHADOW) == 0) {
4313			reflection_property_factory_str(ce, str_name, str_name_len, property_info, return_value);
4314			return;
4315		}
4316	}
4317	zend_throw_exception_ex(reflection_exception_ptr, 0,
4318			"Property %s does not exist", str_name);
4319}
4320/* }}} */
4321
4322/* {{{ _addproperty */
4323static int _addproperty(zval *el, int num_args, va_list args, zend_hash_key *hash_key)
4324{
4325	zval property;
4326	zend_property_info *pptr = (zend_property_info*)Z_PTR_P(el);
4327	zend_class_entry *ce = *va_arg(args, zend_class_entry**);
4328	zval *retval = va_arg(args, zval*);
4329	long filter = va_arg(args, long);
4330
4331	if (pptr->flags	& ZEND_ACC_SHADOW) {
4332		return 0;
4333	}
4334
4335	if (pptr->flags	& filter) {
4336		const char *class_name, *prop_name;
4337		size_t prop_name_len;
4338		zend_unmangle_property_name_ex(pptr->name, &class_name, &prop_name, &prop_name_len);
4339		reflection_property_factory_str(ce, prop_name, prop_name_len, pptr, &property);
4340		add_next_index_zval(retval, &property);
4341	}
4342	return 0;
4343}
4344/* }}} */
4345
4346/* {{{ _adddynproperty */
4347static int _adddynproperty(zval *ptr, int num_args, va_list args, zend_hash_key *hash_key)
4348{
4349	zval property;
4350	zend_class_entry *ce = *va_arg(args, zend_class_entry**);
4351	zval *retval = va_arg(args, zval*);
4352
4353	/* under some circumstances, the properties hash table may contain numeric
4354	 * properties (e.g. when casting from array). This is a WONT FIX bug, at
4355	 * least for the moment. Ignore these */
4356	if (hash_key->key == NULL) {
4357		return 0;
4358	}
4359
4360	if (ZSTR_VAL(hash_key->key)[0] == '\0') {
4361		return 0; /* non public cannot be dynamic */
4362	}
4363
4364	if (zend_get_property_info(ce, hash_key->key, 1) == NULL) {
4365		zend_property_info property_info;
4366
4367		property_info.doc_comment = NULL;
4368		property_info.flags = ZEND_ACC_IMPLICIT_PUBLIC;
4369		property_info.name = hash_key->key;
4370		property_info.ce = ce;
4371		property_info.offset = -1;
4372		reflection_property_factory(ce, hash_key->key, &property_info, &property);
4373		add_next_index_zval(retval, &property);
4374	}
4375	return 0;
4376}
4377/* }}} */
4378
4379/* {{{ proto public ReflectionProperty[] ReflectionClass::getProperties([long $filter])
4380   Returns an array of this class' properties */
4381ZEND_METHOD(reflection_class, getProperties)
4382{
4383	reflection_object *intern;
4384	zend_class_entry *ce;
4385	zend_long filter = 0;
4386	zend_bool filter_is_null = 1;
4387
4388	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4389		return;
4390	}
4391
4392	if (filter_is_null) {
4393		filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC;
4394	}
4395
4396	GET_REFLECTION_OBJECT_PTR(ce);
4397
4398	array_init(return_value);
4399	zend_hash_apply_with_arguments(&ce->properties_info, (apply_func_args_t) _addproperty, 3, &ce, return_value, filter);
4400
4401	if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0 && Z_OBJ_HT(intern->obj)->get_properties) {
4402		HashTable *properties = Z_OBJ_HT(intern->obj)->get_properties(&intern->obj);
4403		zend_hash_apply_with_arguments(properties, (apply_func_args_t) _adddynproperty, 2, &ce, return_value);
4404	}
4405}
4406/* }}} */
4407
4408/* {{{ proto public bool ReflectionClass::hasConstant(string name)
4409   Returns whether a constant exists or not */
4410ZEND_METHOD(reflection_class, hasConstant)
4411{
4412	reflection_object *intern;
4413	zend_class_entry *ce;
4414	zend_string *name;
4415
4416	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4417		return;
4418	}
4419
4420	GET_REFLECTION_OBJECT_PTR(ce);
4421	if (zend_hash_exists(&ce->constants_table, name)) {
4422		RETURN_TRUE;
4423	} else {
4424		RETURN_FALSE;
4425	}
4426}
4427/* }}} */
4428
4429/* {{{ proto public array ReflectionClass::getConstants()
4430   Returns an associative array containing this class' constants and their values */
4431ZEND_METHOD(reflection_class, getConstants)
4432{
4433	reflection_object *intern;
4434	zend_class_entry *ce;
4435	zend_string *key;
4436	zend_class_constant *c;
4437	zval val;
4438
4439	if (zend_parse_parameters_none() == FAILURE) {
4440		return;
4441	}
4442	GET_REFLECTION_OBJECT_PTR(ce);
4443	array_init(return_value);
4444	ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
4445		if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) {
4446			zend_array_destroy(Z_ARRVAL_P(return_value));
4447			RETURN_NULL();
4448		}
4449		ZVAL_COPY_OR_DUP(&val, &c->value);
4450		zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
4451	} ZEND_HASH_FOREACH_END();
4452}
4453/* }}} */
4454
4455/* {{{ proto public array ReflectionClass::getReflectionConstants()
4456   Returns an associative array containing this class' constants as ReflectionClassConstant objects */
4457ZEND_METHOD(reflection_class, getReflectionConstants)
4458{
4459	reflection_object *intern;
4460	zend_class_entry *ce;
4461	zend_string *name;
4462	zend_class_constant *constant;
4463
4464	if (zend_parse_parameters_none() == FAILURE) {
4465		return;
4466	}
4467	GET_REFLECTION_OBJECT_PTR(ce);
4468	array_init(return_value);
4469	ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, name, constant) {
4470		zval class_const;
4471		reflection_class_constant_factory(ce, name, constant, &class_const);
4472		zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &class_const);
4473	} ZEND_HASH_FOREACH_END();
4474}
4475/* }}} */
4476
4477/* {{{ proto public mixed ReflectionClass::getConstant(string name)
4478   Returns the class' constant specified by its name */
4479ZEND_METHOD(reflection_class, getConstant)
4480{
4481	reflection_object *intern;
4482	zend_class_entry *ce;
4483	zend_class_constant *c;
4484	zend_string *name;
4485
4486	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4487		return;
4488	}
4489
4490	GET_REFLECTION_OBJECT_PTR(ce);
4491	ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
4492		if (UNEXPECTED(zval_update_constant_ex(&c->value, ce) != SUCCESS)) {
4493			return;
4494		}
4495	} ZEND_HASH_FOREACH_END();
4496	if ((c = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
4497		RETURN_FALSE;
4498	}
4499	ZVAL_COPY_OR_DUP(return_value, &c->value);
4500}
4501/* }}} */
4502
4503/* {{{ proto public mixed ReflectionClass::getReflectionConstant(string name)
4504   Returns the class' constant as ReflectionClassConstant objects */
4505ZEND_METHOD(reflection_class, getReflectionConstant)
4506{
4507	reflection_object *intern;
4508	zend_class_entry *ce;
4509	zend_class_constant *constant;
4510	zend_string *name;
4511
4512	GET_REFLECTION_OBJECT_PTR(ce);
4513	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4514		return;
4515	}
4516
4517	if ((constant = zend_hash_find_ptr(&ce->constants_table, name)) == NULL) {
4518		RETURN_FALSE;
4519	}
4520	reflection_class_constant_factory(ce, name, constant, return_value);
4521}
4522/* }}} */
4523
4524/* {{{ _class_check_flag */
4525static void _class_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
4526{
4527	reflection_object *intern;
4528	zend_class_entry *ce;
4529
4530	if (zend_parse_parameters_none() == FAILURE) {
4531		return;
4532	}
4533	GET_REFLECTION_OBJECT_PTR(ce);
4534	RETVAL_BOOL(ce->ce_flags & mask);
4535}
4536/* }}} */
4537
4538/* {{{ proto public bool ReflectionClass::isInstantiable()
4539   Returns whether this class is instantiable */
4540ZEND_METHOD(reflection_class, isInstantiable)
4541{
4542	reflection_object *intern;
4543	zend_class_entry *ce;
4544
4545	if (zend_parse_parameters_none() == FAILURE) {
4546		return;
4547	}
4548	GET_REFLECTION_OBJECT_PTR(ce);
4549	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS)) {
4550		RETURN_FALSE;
4551	}
4552
4553	/* Basically, the class is instantiable. Though, if there is a constructor
4554	 * and it is not publicly accessible, it isn't! */
4555	if (!ce->constructor) {
4556		RETURN_TRUE;
4557	}
4558
4559	RETURN_BOOL(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC);
4560}
4561/* }}} */
4562
4563/* {{{ proto public bool ReflectionClass::isCloneable()
4564   Returns whether this class is cloneable */
4565ZEND_METHOD(reflection_class, isCloneable)
4566{
4567	reflection_object *intern;
4568	zend_class_entry *ce;
4569	zval obj;
4570
4571	if (zend_parse_parameters_none() == FAILURE) {
4572		return;
4573	}
4574	GET_REFLECTION_OBJECT_PTR(ce);
4575	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS)) {
4576		RETURN_FALSE;
4577	}
4578	if (!Z_ISUNDEF(intern->obj)) {
4579		if (ce->clone) {
4580			RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4581		} else {
4582			RETURN_BOOL(Z_OBJ_HANDLER(intern->obj, clone_obj) != NULL);
4583		}
4584	} else {
4585		if (ce->clone) {
4586			RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4587		} else {
4588			if (UNEXPECTED(object_init_ex(&obj, ce) != SUCCESS)) {
4589				return;
4590			}
4591			/* We're not calling the constructor, so don't call the destructor either. */
4592			zend_object_store_ctor_failed(Z_OBJ(obj));
4593			RETVAL_BOOL(Z_OBJ_HANDLER(obj, clone_obj) != NULL);
4594			zval_ptr_dtor(&obj);
4595		}
4596	}
4597}
4598/* }}} */
4599
4600/* {{{ proto public bool ReflectionClass::isInterface()
4601   Returns whether this is an interface or a class */
4602ZEND_METHOD(reflection_class, isInterface)
4603{
4604	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_INTERFACE);
4605}
4606/* }}} */
4607
4608/* {{{ proto public bool ReflectionClass::isTrait()
4609   Returns whether this is a trait */
4610ZEND_METHOD(reflection_class, isTrait)
4611{
4612	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT);
4613}
4614/* }}} */
4615
4616/* {{{ proto public bool ReflectionClass::isFinal()
4617   Returns whether this class is final */
4618ZEND_METHOD(reflection_class, isFinal)
4619{
4620	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
4621}
4622/* }}} */
4623
4624/* {{{ proto public bool ReflectionClass::isAbstract()
4625   Returns whether this class is abstract */
4626ZEND_METHOD(reflection_class, isAbstract)
4627{
4628	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
4629}
4630/* }}} */
4631
4632/* {{{ proto public int ReflectionClass::getModifiers()
4633   Returns a bitfield of the access modifiers for this class */
4634ZEND_METHOD(reflection_class, getModifiers)
4635{
4636	reflection_object *intern;
4637	zend_class_entry *ce;
4638	uint32_t keep_flags = ZEND_ACC_FINAL
4639		| ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
4640
4641	if (zend_parse_parameters_none() == FAILURE) {
4642		return;
4643	}
4644	GET_REFLECTION_OBJECT_PTR(ce);
4645
4646	RETURN_LONG((ce->ce_flags & keep_flags));
4647}
4648/* }}} */
4649
4650/* {{{ proto public bool ReflectionClass::isInstance(stdclass object)
4651   Returns whether the given object is an instance of this class */
4652ZEND_METHOD(reflection_class, isInstance)
4653{
4654	reflection_object *intern;
4655	zend_class_entry *ce;
4656	zval *object;
4657
4658	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) {
4659		return;
4660	}
4661	GET_REFLECTION_OBJECT_PTR(ce);
4662	RETURN_BOOL(instanceof_function(Z_OBJCE_P(object), ce));
4663}
4664/* }}} */
4665
4666/* {{{ proto public stdclass ReflectionClass::newInstance(mixed* args, ...)
4667   Returns an instance of this class */
4668ZEND_METHOD(reflection_class, newInstance)
4669{
4670	zval retval;
4671	reflection_object *intern;
4672	zend_class_entry *ce, *old_scope;
4673	zend_function *constructor;
4674
4675	GET_REFLECTION_OBJECT_PTR(ce);
4676
4677	if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
4678		return;
4679	}
4680
4681	old_scope = EG(fake_scope);
4682	EG(fake_scope) = ce;
4683	constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
4684	EG(fake_scope) = old_scope;
4685
4686	/* Run the constructor if there is one */
4687	if (constructor) {
4688		zval *params = NULL;
4689		int ret, i, num_args = 0;
4690		zend_fcall_info fci;
4691		zend_fcall_info_cache fcc;
4692
4693		if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
4694			zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
4695			zval_ptr_dtor(return_value);
4696			RETURN_NULL();
4697		}
4698
4699		if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &params, &num_args) == FAILURE) {
4700			zval_ptr_dtor(return_value);
4701			RETURN_FALSE;
4702		}
4703
4704		for (i = 0; i < num_args; i++) {
4705			Z_TRY_ADDREF(params[i]);
4706		}
4707
4708		fci.size = sizeof(fci);
4709		ZVAL_UNDEF(&fci.function_name);
4710		fci.object = Z_OBJ_P(return_value);
4711		fci.retval = &retval;
4712		fci.param_count = num_args;
4713		fci.params = params;
4714		fci.no_separation = 1;
4715
4716		fcc.function_handler = constructor;
4717		fcc.called_scope = Z_OBJCE_P(return_value);
4718		fcc.object = Z_OBJ_P(return_value);
4719
4720		ret = zend_call_function(&fci, &fcc);
4721		zval_ptr_dtor(&retval);
4722		for (i = 0; i < num_args; i++) {
4723			zval_ptr_dtor(&params[i]);
4724		}
4725
4726		if (EG(exception)) {
4727			zend_object_store_ctor_failed(Z_OBJ_P(return_value));
4728		}
4729		if (ret == FAILURE) {
4730			php_error_docref(NULL, E_WARNING, "Invocation of %s's constructor failed", ZSTR_VAL(ce->name));
4731			zval_ptr_dtor(return_value);
4732			RETURN_NULL();
4733		}
4734	} else if (ZEND_NUM_ARGS()) {
4735		zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ZSTR_VAL(ce->name));
4736	}
4737}
4738/* }}} */
4739
4740/* {{{ proto public stdclass ReflectionClass::newInstanceWithoutConstructor()
4741   Returns an instance of this class without invoking its constructor */
4742ZEND_METHOD(reflection_class, newInstanceWithoutConstructor)
4743{
4744	reflection_object *intern;
4745	zend_class_entry *ce;
4746
4747	GET_REFLECTION_OBJECT_PTR(ce);
4748
4749	if (ce->create_object != NULL && ce->ce_flags & ZEND_ACC_FINAL) {
4750		zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s is an internal class marked as final that cannot be instantiated without invoking its constructor", ZSTR_VAL(ce->name));
4751		return;
4752	}
4753
4754	object_init_ex(return_value, ce);
4755}
4756/* }}} */
4757
4758/* {{{ proto public stdclass ReflectionClass::newInstanceArgs([array args])
4759   Returns an instance of this class */
4760ZEND_METHOD(reflection_class, newInstanceArgs)
4761{
4762	zval retval, *val;
4763	reflection_object *intern;
4764	zend_class_entry *ce, *old_scope;
4765	int ret, i, argc = 0;
4766	HashTable *args;
4767	zend_function *constructor;
4768
4769	GET_REFLECTION_OBJECT_PTR(ce);
4770
4771	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|h", &args) == FAILURE) {
4772		return;
4773	}
4774
4775	if (ZEND_NUM_ARGS() > 0) {
4776		argc = args->nNumOfElements;
4777	}
4778
4779	if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
4780		return;
4781	}
4782
4783	old_scope = EG(fake_scope);
4784	EG(fake_scope) = ce;
4785	constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
4786	EG(fake_scope) = old_scope;
4787
4788	/* Run the constructor if there is one */
4789	if (constructor) {
4790		zval *params = NULL;
4791		zend_fcall_info fci;
4792		zend_fcall_info_cache fcc;
4793
4794		if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
4795			zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
4796			zval_ptr_dtor(return_value);
4797			RETURN_NULL();
4798		}
4799
4800		if (argc) {
4801			params = safe_emalloc(sizeof(zval), argc, 0);
4802			argc = 0;
4803			ZEND_HASH_FOREACH_VAL(args, val) {
4804				ZVAL_COPY(&params[argc], val);
4805				argc++;
4806			} ZEND_HASH_FOREACH_END();
4807		}
4808
4809		fci.size = sizeof(fci);
4810		ZVAL_UNDEF(&fci.function_name);
4811		fci.object = Z_OBJ_P(return_value);
4812		fci.retval = &retval;
4813		fci.param_count = argc;
4814		fci.params = params;
4815		fci.no_separation = 1;
4816
4817		fcc.function_handler = constructor;
4818		fcc.called_scope = Z_OBJCE_P(return_value);
4819		fcc.object = Z_OBJ_P(return_value);
4820
4821		ret = zend_call_function(&fci, &fcc);
4822		zval_ptr_dtor(&retval);
4823		if (params) {
4824			for (i = 0; i < argc; i++) {
4825				zval_ptr_dtor(&params[i]);
4826			}
4827			efree(params);
4828		}
4829
4830		if (EG(exception)) {
4831			zend_object_store_ctor_failed(Z_OBJ_P(return_value));
4832		}
4833		if (ret == FAILURE) {
4834			zval_ptr_dtor(&retval);
4835			php_error_docref(NULL, E_WARNING, "Invocation of %s's constructor failed", ZSTR_VAL(ce->name));
4836			zval_ptr_dtor(return_value);
4837			RETURN_NULL();
4838		}
4839	} else if (argc) {
4840		zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ZSTR_VAL(ce->name));
4841	}
4842}
4843/* }}} */
4844
4845/* {{{ proto public ReflectionClass[] ReflectionClass::getInterfaces()
4846   Returns an array of interfaces this class implements */
4847ZEND_METHOD(reflection_class, getInterfaces)
4848{
4849	reflection_object *intern;
4850	zend_class_entry *ce;
4851
4852	if (zend_parse_parameters_none() == FAILURE) {
4853		return;
4854	}
4855	GET_REFLECTION_OBJECT_PTR(ce);
4856
4857	if (ce->num_interfaces) {
4858		uint32_t i;
4859
4860		array_init(return_value);
4861		for (i=0; i < ce->num_interfaces; i++) {
4862			zval interface;
4863			zend_reflection_class_factory(ce->interfaces[i], &interface);
4864			zend_hash_update(Z_ARRVAL_P(return_value), ce->interfaces[i]->name, &interface);
4865		}
4866	} else {
4867		ZVAL_EMPTY_ARRAY(return_value);
4868	}
4869}
4870/* }}} */
4871
4872/* {{{ proto public String[] ReflectionClass::getInterfaceNames()
4873   Returns an array of names of interfaces this class implements */
4874ZEND_METHOD(reflection_class, getInterfaceNames)
4875{
4876	reflection_object *intern;
4877	zend_class_entry *ce;
4878	uint32_t i;
4879
4880	if (zend_parse_parameters_none() == FAILURE) {
4881		return;
4882	}
4883	GET_REFLECTION_OBJECT_PTR(ce);
4884
4885	if (!ce->num_interfaces) {
4886		/* Return an empty array if this class implements no interfaces */
4887		ZVAL_EMPTY_ARRAY(return_value);
4888		return;
4889	}
4890
4891	array_init(return_value);
4892
4893	for (i=0; i < ce->num_interfaces; i++) {
4894		add_next_index_str(return_value, zend_string_copy(ce->interfaces[i]->name));
4895	}
4896}
4897/* }}} */
4898
4899/* {{{ proto public ReflectionClass[] ReflectionClass::getTraits()
4900   Returns an array of traits used by this class */
4901ZEND_METHOD(reflection_class, getTraits)
4902{
4903	reflection_object *intern;
4904	zend_class_entry *ce;
4905	uint32_t i;
4906
4907	if (zend_parse_parameters_none() == FAILURE) {
4908		return;
4909	}
4910	GET_REFLECTION_OBJECT_PTR(ce);
4911
4912	if (!ce->num_traits) {
4913		ZVAL_EMPTY_ARRAY(return_value);
4914		return;
4915	}
4916
4917	array_init(return_value);
4918
4919	for (i=0; i < ce->num_traits; i++) {
4920		zval trait;
4921		zend_reflection_class_factory(ce->traits[i], &trait);
4922		zend_hash_update(Z_ARRVAL_P(return_value), ce->traits[i]->name, &trait);
4923	}
4924}
4925/* }}} */
4926
4927/* {{{ proto public String[] ReflectionClass::getTraitNames()
4928   Returns an array of names of traits used by this class */
4929ZEND_METHOD(reflection_class, getTraitNames)
4930{
4931	reflection_object *intern;
4932	zend_class_entry *ce;
4933	uint32_t i;
4934
4935	if (zend_parse_parameters_none() == FAILURE) {
4936		return;
4937	}
4938	GET_REFLECTION_OBJECT_PTR(ce);
4939
4940	if (!ce->num_traits) {
4941		ZVAL_EMPTY_ARRAY(return_value);
4942		return;
4943	}
4944
4945	array_init(return_value);
4946
4947	for (i=0; i < ce->num_traits; i++) {
4948		add_next_index_str(return_value, zend_string_copy(ce->traits[i]->name));
4949	}
4950}
4951/* }}} */
4952
4953/* {{{ proto public array ReflectionClass::getTraitAliases()
4954   Returns an array of trait aliases */
4955ZEND_METHOD(reflection_class, getTraitAliases)
4956{
4957	reflection_object *intern;
4958	zend_class_entry *ce;
4959
4960	if (zend_parse_parameters_none() == FAILURE) {
4961		return;
4962	}
4963	GET_REFLECTION_OBJECT_PTR(ce);
4964
4965
4966	if (ce->trait_aliases) {
4967		uint32_t i = 0;
4968
4969		array_init(return_value);
4970		while (ce->trait_aliases[i]) {
4971			zend_string *mname;
4972			zend_trait_method_reference *cur_ref = &ce->trait_aliases[i]->trait_method;
4973
4974			if (ce->trait_aliases[i]->alias) {
4975
4976				mname = zend_string_alloc(ZSTR_LEN(cur_ref->class_name) + ZSTR_LEN(cur_ref->method_name) + 2, 0);
4977				snprintf(ZSTR_VAL(mname), ZSTR_LEN(mname) + 1, "%s::%s", ZSTR_VAL(cur_ref->class_name), ZSTR_VAL(cur_ref->method_name));
4978				add_assoc_str_ex(return_value, ZSTR_VAL(ce->trait_aliases[i]->alias), ZSTR_LEN(ce->trait_aliases[i]->alias), mname);
4979			}
4980			i++;
4981		}
4982	} else {
4983		ZVAL_EMPTY_ARRAY(return_value);
4984	}
4985}
4986/* }}} */
4987
4988/* {{{ proto public ReflectionClass ReflectionClass::getParentClass()
4989   Returns the class' parent class, or, if none exists, FALSE */
4990ZEND_METHOD(reflection_class, getParentClass)
4991{
4992	reflection_object *intern;
4993	zend_class_entry *ce;
4994
4995	if (zend_parse_parameters_none() == FAILURE) {
4996		return;
4997	}
4998	GET_REFLECTION_OBJECT_PTR(ce);
4999
5000	if (ce->parent) {
5001		zend_reflection_class_factory(ce->parent, return_value);
5002	} else {
5003		RETURN_FALSE;
5004	}
5005}
5006/* }}} */
5007
5008/* {{{ proto public bool ReflectionClass::isSubclassOf(string|ReflectionClass class)
5009   Returns whether this class is a subclass of another class */
5010ZEND_METHOD(reflection_class, isSubclassOf)
5011{
5012	reflection_object *intern, *argument;
5013	zend_class_entry *ce, *class_ce;
5014	zval *class_name;
5015
5016	GET_REFLECTION_OBJECT_PTR(ce);
5017
5018	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &class_name) == FAILURE) {
5019		return;
5020	}
5021
5022	switch (Z_TYPE_P(class_name)) {
5023		case IS_STRING:
5024			if ((class_ce = zend_lookup_class(Z_STR_P(class_name))) == NULL) {
5025				zend_throw_exception_ex(reflection_exception_ptr, 0,
5026						"Class %s does not exist", Z_STRVAL_P(class_name));
5027				return;
5028			}
5029			break;
5030		case IS_OBJECT:
5031			if (instanceof_function(Z_OBJCE_P(class_name), reflection_class_ptr)) {
5032				argument = Z_REFLECTION_P(class_name);
5033				if (argument->ptr == NULL) {
5034					zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5035					return;
5036				}
5037				class_ce = argument->ptr;
5038				break;
5039			}
5040			/* no break */
5041		default:
5042			zend_throw_exception_ex(reflection_exception_ptr, 0,
5043					"Parameter one must either be a string or a ReflectionClass object");
5044			return;
5045	}
5046
5047	RETURN_BOOL((ce != class_ce && instanceof_function(ce, class_ce)));
5048}
5049/* }}} */
5050
5051/* {{{ proto public bool ReflectionClass::implementsInterface(string|ReflectionClass interface_name)
5052   Returns whether this class is a subclass of another class */
5053ZEND_METHOD(reflection_class, implementsInterface)
5054{
5055	reflection_object *intern, *argument;
5056	zend_class_entry *ce, *interface_ce;
5057	zval *interface;
5058
5059	GET_REFLECTION_OBJECT_PTR(ce);
5060
5061	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &interface) == FAILURE) {
5062		return;
5063	}
5064
5065	switch (Z_TYPE_P(interface)) {
5066		case IS_STRING:
5067			if ((interface_ce = zend_lookup_class(Z_STR_P(interface))) == NULL) {
5068				zend_throw_exception_ex(reflection_exception_ptr, 0,
5069						"Interface %s does not exist", Z_STRVAL_P(interface));
5070				return;
5071			}
5072			break;
5073		case IS_OBJECT:
5074			if (instanceof_function(Z_OBJCE_P(interface), reflection_class_ptr)) {
5075				argument = Z_REFLECTION_P(interface);
5076				if (argument->ptr == NULL) {
5077					zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5078					return;
5079				}
5080				interface_ce = argument->ptr;
5081				break;
5082			}
5083			/* no break */
5084		default:
5085			zend_throw_exception_ex(reflection_exception_ptr, 0,
5086					"Parameter one must either be a string or a ReflectionClass object");
5087			return;
5088	}
5089
5090	if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) {
5091		zend_throw_exception_ex(reflection_exception_ptr, 0,
5092				"%s is not an interface", ZSTR_VAL(interface_ce->name));
5093		return;
5094	}
5095	RETURN_BOOL(instanceof_function(ce, interface_ce));
5096}
5097/* }}} */
5098
5099/* {{{ proto public bool ReflectionClass::isIterable()
5100   Returns whether this class is iterable (can be used inside foreach) */
5101ZEND_METHOD(reflection_class, isIterable)
5102{
5103	reflection_object *intern;
5104	zend_class_entry *ce;
5105
5106	if (zend_parse_parameters_none() == FAILURE) {
5107		return;
5108	}
5109
5110	GET_REFLECTION_OBJECT_PTR(ce);
5111
5112	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS |
5113	                    ZEND_ACC_TRAIT     | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
5114		RETURN_FALSE;
5115	}
5116
5117	RETURN_BOOL(ce->get_iterator || instanceof_function(ce, zend_ce_traversable));
5118}
5119/* }}} */
5120
5121/* {{{ proto public ReflectionExtension|NULL ReflectionClass::getExtension()
5122   Returns NULL or the extension the class belongs to */
5123ZEND_METHOD(reflection_class, getExtension)
5124{
5125	reflection_object *intern;
5126	zend_class_entry *ce;
5127
5128	if (zend_parse_parameters_none() == FAILURE) {
5129		return;
5130	}
5131
5132	GET_REFLECTION_OBJECT_PTR(ce);
5133
5134	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5135		reflection_extension_factory(return_value, ce->info.internal.module->name);
5136	}
5137}
5138/* }}} */
5139
5140/* {{{ proto public string|false ReflectionClass::getExtensionName()
5141   Returns false or the name of the extension the class belongs to */
5142ZEND_METHOD(reflection_class, getExtensionName)
5143{
5144	reflection_object *intern;
5145	zend_class_entry *ce;
5146
5147	if (zend_parse_parameters_none() == FAILURE) {
5148		return;
5149	}
5150
5151	GET_REFLECTION_OBJECT_PTR(ce);
5152
5153	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5154		RETURN_STRING(ce->info.internal.module->name);
5155	} else {
5156		RETURN_FALSE;
5157	}
5158}
5159/* }}} */
5160
5161/* {{{ proto public bool ReflectionClass::inNamespace()
5162   Returns whether this class is defined in namespace */
5163ZEND_METHOD(reflection_class, inNamespace)
5164{
5165	zval *name;
5166	const char *backslash;
5167
5168	if (zend_parse_parameters_none() == FAILURE) {
5169		return;
5170	}
5171	if ((name = _default_load_name(getThis())) == NULL) {
5172		RETURN_FALSE;
5173	}
5174	if (Z_TYPE_P(name) == IS_STRING
5175		&& (backslash = zend_memrchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name)))
5176		&& backslash > Z_STRVAL_P(name))
5177	{
5178		RETURN_TRUE;
5179	}
5180	RETURN_FALSE;
5181}
5182/* }}} */
5183
5184/* {{{ proto public string ReflectionClass::getNamespaceName()
5185   Returns the name of namespace where this class is defined */
5186ZEND_METHOD(reflection_class, getNamespaceName)
5187{
5188	zval *name;
5189	const char *backslash;
5190
5191	if (zend_parse_parameters_none() == FAILURE) {
5192		return;
5193	}
5194	if ((name = _default_load_name(getThis())) == NULL) {
5195		RETURN_FALSE;
5196	}
5197	if (Z_TYPE_P(name) == IS_STRING
5198		&& (backslash = zend_memrchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name)))
5199		&& backslash > Z_STRVAL_P(name))
5200	{
5201		RETURN_STRINGL(Z_STRVAL_P(name), backslash - Z_STRVAL_P(name));
5202	}
5203	RETURN_EMPTY_STRING();
5204}
5205/* }}} */
5206
5207/* {{{ proto public string ReflectionClass::getShortName()
5208   Returns the short name of the class (without namespace part) */
5209ZEND_METHOD(reflection_class, getShortName)
5210{
5211	zval *name;
5212	const char *backslash;
5213
5214	if (zend_parse_parameters_none() == FAILURE) {
5215		return;
5216	}
5217	if ((name = _default_load_name(getThis())) == NULL) {
5218		RETURN_FALSE;
5219	}
5220	if (Z_TYPE_P(name) == IS_STRING
5221		&& (backslash = zend_memrchr(Z_STRVAL_P(name), '\\', Z_STRLEN_P(name)))
5222		&& backslash > Z_STRVAL_P(name))
5223	{
5224		RETURN_STRINGL(backslash + 1, Z_STRLEN_P(name) - (backslash - Z_STRVAL_P(name) + 1));
5225	}
5226	ZVAL_COPY_DEREF(return_value, name);
5227}
5228/* }}} */
5229
5230/* {{{ proto public static mixed ReflectionObject::export(mixed argument [, bool return]) throws ReflectionException
5231   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
5232ZEND_METHOD(reflection_object, export)
5233{
5234	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_object_ptr, 1);
5235}
5236/* }}} */
5237
5238/* {{{ proto public void ReflectionObject::__construct(mixed argument) throws ReflectionException
5239   Constructor. Takes an instance as an argument */
5240ZEND_METHOD(reflection_object, __construct)
5241{
5242	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
5243}
5244/* }}} */
5245
5246/* {{{ proto public static mixed ReflectionProperty::export(mixed class, string name [, bool return]) throws ReflectionException
5247   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
5248ZEND_METHOD(reflection_property, export)
5249{
5250	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_property_ptr, 2);
5251}
5252/* }}} */
5253
5254/* {{{ proto public static mixed ReflectionClassConstant::export(mixed class, string name [, bool return]) throws ReflectionException
5255   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
5256ZEND_METHOD(reflection_class_constant, export)
5257{
5258	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_class_constant_ptr, 2);
5259}
5260/* }}} */
5261
5262/* {{{ proto public void ReflectionProperty::__construct(mixed class, string name)
5263   Constructor. Throws an Exception in case the given property does not exist */
5264ZEND_METHOD(reflection_property, __construct)
5265{
5266	zval propname, cname, *classname;
5267	zend_string *name;
5268	int dynam_prop = 0;
5269	zval *object;
5270	reflection_object *intern;
5271	zend_class_entry *ce;
5272	zend_property_info *property_info = NULL;
5273	property_reference *reference;
5274
5275	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zS", &classname, &name) == FAILURE) {
5276		return;
5277	}
5278
5279	object = getThis();
5280	intern = Z_REFLECTION_P(object);
5281
5282	/* Find the class entry */
5283	switch (Z_TYPE_P(classname)) {
5284		case IS_STRING:
5285			if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
5286				zend_throw_exception_ex(reflection_exception_ptr, 0,
5287						"Class %s does not exist", Z_STRVAL_P(classname));
5288				return;
5289			}
5290			break;
5291
5292		case IS_OBJECT:
5293			ce = Z_OBJCE_P(classname);
5294			break;
5295
5296		default:
5297			_DO_THROW("The parameter class is expected to be either a string or an object");
5298			/* returns out of this function */
5299	}
5300
5301	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) == NULL || (property_info->flags & ZEND_ACC_SHADOW)) {
5302		/* Check for dynamic properties */
5303		if (property_info == NULL && Z_TYPE_P(classname) == IS_OBJECT && Z_OBJ_HT_P(classname)->get_properties) {
5304			if (zend_hash_exists(Z_OBJ_HT_P(classname)->get_properties(classname), name)) {
5305				dynam_prop = 1;
5306			}
5307		}
5308		if (dynam_prop == 0) {
5309			zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
5310			return;
5311		}
5312	}
5313
5314	if (dynam_prop == 0 && (property_info->flags & ZEND_ACC_PRIVATE) == 0) {
5315		/* we have to search the class hierarchy for this (implicit) public or protected property */
5316		zend_class_entry *tmp_ce = ce;
5317		zend_property_info *tmp_info;
5318
5319		while (tmp_ce && (tmp_info = zend_hash_find_ptr(&tmp_ce->properties_info, name)) == NULL) {
5320			ce = tmp_ce;
5321			property_info = tmp_info;
5322			tmp_ce = tmp_ce->parent;
5323		}
5324	}
5325
5326	if (dynam_prop == 0) {
5327		ZVAL_STR_COPY(&cname, property_info->ce->name);
5328	} else {
5329		ZVAL_STR_COPY(&cname, ce->name);
5330	}
5331	reflection_update_property_class(object, &cname);
5332
5333	ZVAL_STR_COPY(&propname, name);
5334	reflection_update_property_name(object, &propname);
5335
5336	reference = (property_reference*) emalloc(sizeof(property_reference));
5337	if (dynam_prop) {
5338		reference->prop.flags = ZEND_ACC_IMPLICIT_PUBLIC;
5339		reference->prop.name = name;
5340		reference->prop.doc_comment = NULL;
5341		reference->prop.ce = ce;
5342	} else {
5343		reference->prop = *property_info;
5344	}
5345	reference->ce = ce;
5346	reference->unmangled_name = zend_string_copy(name);
5347	intern->ptr = reference;
5348	intern->ref_type = REF_TYPE_PROPERTY;
5349	intern->ce = ce;
5350	intern->ignore_visibility = 0;
5351}
5352/* }}} */
5353
5354/* {{{ proto public string ReflectionProperty::__toString()
5355   Returns a string representation */
5356ZEND_METHOD(reflection_property, __toString)
5357{
5358	reflection_object *intern;
5359	property_reference *ref;
5360	smart_str str = {0};
5361
5362	if (zend_parse_parameters_none() == FAILURE) {
5363		return;
5364	}
5365	GET_REFLECTION_OBJECT_PTR(ref);
5366	_property_string(&str, &ref->prop, ZSTR_VAL(ref->unmangled_name), "");
5367	RETURN_STR(smart_str_extract(&str));
5368}
5369/* }}} */
5370
5371/* {{{ proto public string ReflectionProperty::getName()
5372   Returns the class' name */
5373ZEND_METHOD(reflection_property, getName)
5374{
5375	if (zend_parse_parameters_none() == FAILURE) {
5376		return;
5377	}
5378	_default_get_name(getThis(), return_value);
5379}
5380/* }}} */
5381
5382static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
5383{
5384	reflection_object *intern;
5385	property_reference *ref;
5386
5387	if (zend_parse_parameters_none() == FAILURE) {
5388		return;
5389	}
5390	GET_REFLECTION_OBJECT_PTR(ref);
5391	RETURN_BOOL(ref->prop.flags & mask);
5392}
5393/* }}} */
5394
5395/* {{{ proto public bool ReflectionProperty::isPublic()
5396   Returns whether this property is public */
5397ZEND_METHOD(reflection_property, isPublic)
5398{
5399	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC);
5400}
5401/* }}} */
5402
5403/* {{{ proto public bool ReflectionProperty::isPrivate()
5404   Returns whether this property is private */
5405ZEND_METHOD(reflection_property, isPrivate)
5406{
5407	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
5408}
5409/* }}} */
5410
5411/* {{{ proto public bool ReflectionProperty::isProtected()
5412   Returns whether this property is protected */
5413ZEND_METHOD(reflection_property, isProtected)
5414{
5415	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
5416}
5417/* }}} */
5418
5419/* {{{ proto public bool ReflectionProperty::isStatic()
5420   Returns whether this property is static */
5421ZEND_METHOD(reflection_property, isStatic)
5422{
5423	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
5424}
5425/* }}} */
5426
5427/* {{{ proto public bool ReflectionProperty::isDefault()
5428   Returns whether this property is default (declared at compilation time). */
5429ZEND_METHOD(reflection_property, isDefault)
5430{
5431	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ~ZEND_ACC_IMPLICIT_PUBLIC);
5432}
5433/* }}} */
5434
5435/* {{{ proto public int ReflectionProperty::getModifiers()
5436   Returns a bitfield of the access modifiers for this property */
5437ZEND_METHOD(reflection_property, getModifiers)
5438{
5439	reflection_object *intern;
5440	property_reference *ref;
5441	uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_IMPLICIT_PUBLIC | ZEND_ACC_STATIC;
5442
5443	if (zend_parse_parameters_none() == FAILURE) {
5444		return;
5445	}
5446	GET_REFLECTION_OBJECT_PTR(ref);
5447
5448	RETURN_LONG((ref->prop.flags & keep_flags));
5449}
5450/* }}} */
5451
5452/* {{{ proto public mixed ReflectionProperty::getValue([stdclass object])
5453   Returns this property's value */
5454ZEND_METHOD(reflection_property, getValue)
5455{
5456	reflection_object *intern;
5457	property_reference *ref;
5458	zval *object, *name;
5459	zval *member_p = NULL;
5460
5461	GET_REFLECTION_OBJECT_PTR(ref);
5462
5463	if (!(ref->prop.flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) {
5464		name = _default_load_name(getThis());
5465		zend_throw_exception_ex(reflection_exception_ptr, 0,
5466			"Cannot access non-public member %s::$%s", ZSTR_VAL(intern->ce->name), Z_STRVAL_P(name));
5467		return;
5468	}
5469
5470	if (ref->prop.flags & ZEND_ACC_STATIC) {
5471		member_p = zend_read_static_property_ex(ref->ce, ref->unmangled_name, 0);
5472		if (member_p) {
5473			ZVAL_COPY_DEREF(return_value, member_p);
5474		}
5475	} else {
5476		zval rv;
5477
5478		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) {
5479			return;
5480		}
5481
5482		if (!instanceof_function(Z_OBJCE_P(object), ref->prop.ce)) {
5483			_DO_THROW("Given object is not an instance of the class this property was declared in");
5484			/* Returns from this function */
5485		}
5486
5487		member_p = zend_read_property_ex(ref->ce, object, ref->unmangled_name, 0, &rv);
5488		if (member_p != &rv) {
5489			ZVAL_COPY_DEREF(return_value, member_p);
5490		} else {
5491			if (Z_ISREF_P(member_p)) {
5492				zend_unwrap_reference(member_p);
5493			}
5494			ZVAL_COPY_VALUE(return_value, member_p);
5495		}
5496	}
5497}
5498/* }}} */
5499
5500/* {{{ proto public void ReflectionProperty::setValue([stdclass object,] mixed value)
5501   Sets this property's value */
5502ZEND_METHOD(reflection_property, setValue)
5503{
5504	reflection_object *intern;
5505	property_reference *ref;
5506	zval *object, *name;
5507	zval *value;
5508	zval *tmp;
5509
5510	GET_REFLECTION_OBJECT_PTR(ref);
5511
5512	if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) {
5513		name = _default_load_name(getThis());
5514		zend_throw_exception_ex(reflection_exception_ptr, 0,
5515			"Cannot access non-public member %s::$%s", ZSTR_VAL(intern->ce->name), Z_STRVAL_P(name));
5516		return;
5517	}
5518
5519	if (ref->prop.flags & ZEND_ACC_STATIC) {
5520		if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
5521			if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &tmp, &value) == FAILURE) {
5522				return;
5523			}
5524		}
5525
5526		zend_update_static_property_ex(ref->ce, ref->unmangled_name, value);
5527	} else {
5528		if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) {
5529			return;
5530		}
5531
5532		zend_update_property_ex(ref->ce, object, ref->unmangled_name, value);
5533	}
5534}
5535/* }}} */
5536
5537/* {{{ proto public ReflectionClass ReflectionProperty::getDeclaringClass()
5538   Get the declaring class */
5539ZEND_METHOD(reflection_property, getDeclaringClass)
5540{
5541	reflection_object *intern;
5542	property_reference *ref;
5543	zend_class_entry *tmp_ce, *ce;
5544	zend_property_info *tmp_info;
5545
5546	if (zend_parse_parameters_none() == FAILURE) {
5547		return;
5548	}
5549	GET_REFLECTION_OBJECT_PTR(ref);
5550
5551	ce = tmp_ce = ref->ce;
5552	while (tmp_ce && (tmp_info = zend_hash_find_ptr(&tmp_ce->properties_info, ref->unmangled_name)) != NULL) {
5553		if (tmp_info->flags & ZEND_ACC_PRIVATE || tmp_info->flags & ZEND_ACC_SHADOW) {
5554			/* it's a private property, so it can't be inherited */
5555			break;
5556		}
5557		ce = tmp_ce;
5558		if (tmp_ce == tmp_info->ce) {
5559			/* declared in this class, done */
5560			break;
5561		}
5562		tmp_ce = tmp_ce->parent;
5563	}
5564
5565	zend_reflection_class_factory(ce, return_value);
5566}
5567/* }}} */
5568
5569/* {{{ proto public string ReflectionProperty::getDocComment()
5570   Returns the doc comment for this property */
5571ZEND_METHOD(reflection_property, getDocComment)
5572{
5573	reflection_object *intern;
5574	property_reference *ref;
5575
5576	if (zend_parse_parameters_none() == FAILURE) {
5577		return;
5578	}
5579	GET_REFLECTION_OBJECT_PTR(ref);
5580	if (ref->prop.doc_comment) {
5581		RETURN_STR_COPY(ref->prop.doc_comment);
5582	}
5583	RETURN_FALSE;
5584}
5585/* }}} */
5586
5587/* {{{ proto public int ReflectionProperty::setAccessible(bool visible)
5588   Sets whether non-public properties can be requested */
5589ZEND_METHOD(reflection_property, setAccessible)
5590{
5591	reflection_object *intern;
5592	zend_bool visible;
5593
5594	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
5595		return;
5596	}
5597
5598	intern = Z_REFLECTION_P(getThis());
5599
5600	intern->ignore_visibility = visible;
5601}
5602/* }}} */
5603
5604/* {{{ proto public static mixed ReflectionExtension::export(string name [, bool return]) throws ReflectionException
5605   Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
5606ZEND_METHOD(reflection_extension, export)
5607{
5608	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_extension_ptr, 1);
5609}
5610/* }}} */
5611
5612/* {{{ proto public void ReflectionExtension::__construct(string name)
5613   Constructor. Throws an Exception in case the given extension does not exist */
5614ZEND_METHOD(reflection_extension, __construct)
5615{
5616	zval name;
5617	zval *object;
5618	char *lcname;
5619	reflection_object *intern;
5620	zend_module_entry *module;
5621	char *name_str;
5622	size_t name_len;
5623	ALLOCA_FLAG(use_heap)
5624
5625	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
5626		return;
5627	}
5628
5629	object = getThis();
5630	intern = Z_REFLECTION_P(object);
5631	lcname = do_alloca(name_len + 1, use_heap);
5632	zend_str_tolower_copy(lcname, name_str, name_len);
5633	if ((module = zend_hash_str_find_ptr(&module_registry, lcname, name_len)) == NULL) {
5634		free_alloca(lcname, use_heap);
5635		zend_throw_exception_ex(reflection_exception_ptr, 0,
5636			"Extension %s does not exist", name_str);
5637		return;
5638	}
5639	free_alloca(lcname, use_heap);
5640	ZVAL_STRING(&name, module->name);
5641	reflection_update_property_name(object, &name);
5642	intern->ptr = module;
5643	intern->ref_type = REF_TYPE_OTHER;
5644	intern->ce = NULL;
5645}
5646/* }}} */
5647
5648/* {{{ proto public string ReflectionExtension::__toString()
5649   Returns a string representation */
5650ZEND_METHOD(reflection_extension, __toString)
5651{
5652	reflection_object *intern;
5653	zend_module_entry *module;
5654	smart_str str = {0};
5655
5656	if (zend_parse_parameters_none() == FAILURE) {
5657		return;
5658	}
5659	GET_REFLECTION_OBJECT_PTR(module);
5660	_extension_string(&str, module, "");
5661	RETURN_STR(smart_str_extract(&str));
5662}
5663/* }}} */
5664
5665/* {{{ proto public string ReflectionExtension::getName()
5666   Returns this extension's name */
5667ZEND_METHOD(reflection_extension, getName)
5668{
5669	if (zend_parse_parameters_none() == FAILURE) {
5670		return;
5671	}
5672	_default_get_name(getThis(), return_value);
5673}
5674/* }}} */
5675
5676/* {{{ proto public string ReflectionExtension::getVersion()
5677   Returns this extension's version */
5678ZEND_METHOD(reflection_extension, getVersion)
5679{
5680	reflection_object *intern;
5681	zend_module_entry *module;
5682
5683	if (zend_parse_parameters_none() == FAILURE) {
5684		return;
5685	}
5686	GET_REFLECTION_OBJECT_PTR(module);
5687
5688	/* An extension does not necessarily have a version number */
5689	if (module->version == NO_VERSION_YET) {
5690		RETURN_NULL();
5691	} else {
5692		RETURN_STRING(module->version);
5693	}
5694}
5695/* }}} */
5696
5697/* {{{ proto public ReflectionFunction[] ReflectionExtension::getFunctions()
5698   Returns an array of this extension's functions */
5699ZEND_METHOD(reflection_extension, getFunctions)
5700{
5701	reflection_object *intern;
5702	zend_module_entry *module;
5703	zval function;
5704	zend_function *fptr;
5705
5706	if (zend_parse_parameters_none() == FAILURE) {
5707		return;
5708	}
5709	GET_REFLECTION_OBJECT_PTR(module);
5710
5711	array_init(return_value);
5712	ZEND_HASH_FOREACH_PTR(CG(function_table), fptr) {
5713		if (fptr->common.type==ZEND_INTERNAL_FUNCTION
5714			&& fptr->internal_function.module == module) {
5715			reflection_function_factory(fptr, NULL, &function);
5716			zend_hash_update(Z_ARRVAL_P(return_value), fptr->common.function_name, &function);
5717		}
5718	} ZEND_HASH_FOREACH_END();
5719}
5720/* }}} */
5721
5722static int _addconstant(zval *el, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
5723{
5724	zval const_val;
5725	zend_constant *constant = (zend_constant*)Z_PTR_P(el);
5726	zval *retval = va_arg(args, zval*);
5727	int number = va_arg(args, int);
5728
5729	if (number == ZEND_CONSTANT_MODULE_NUMBER(constant)) {
5730		ZVAL_COPY_OR_DUP(&const_val, &constant->value);
5731		zend_hash_update(Z_ARRVAL_P(retval), constant->name, &const_val);
5732	}
5733	return 0;
5734}
5735/* }}} */
5736
5737/* {{{ proto public array ReflectionExtension::getConstants()
5738   Returns an associative array containing this extension's constants and their values */
5739ZEND_METHOD(reflection_extension, getConstants)
5740{
5741	reflection_object *intern;
5742	zend_module_entry *module;
5743
5744	if (zend_parse_parameters_none() == FAILURE) {
5745		return;
5746	}
5747	GET_REFLECTION_OBJECT_PTR(module);
5748
5749	array_init(return_value);
5750	zend_hash_apply_with_arguments(EG(zend_constants), (apply_func_args_t) _addconstant, 2, return_value, module->module_number);
5751}
5752/* }}} */
5753
5754/* {{{ _addinientry */
5755static int _addinientry(zval *el, int num_args, va_list args, zend_hash_key *hash_key)
5756{
5757	zend_ini_entry *ini_entry = (zend_ini_entry*)Z_PTR_P(el);
5758	zval *retval = va_arg(args, zval*);
5759	int number = va_arg(args, int);
5760
5761	if (number == ini_entry->module_number) {
5762		if (ini_entry->value) {
5763			zval zv;
5764
5765			ZVAL_STR_COPY(&zv, ini_entry->value);
5766			zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &zv);
5767		} else {
5768			zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &EG(uninitialized_zval));
5769		}
5770	}
5771	return ZEND_HASH_APPLY_KEEP;
5772}
5773/* }}} */
5774
5775/* {{{ proto public array ReflectionExtension::getINIEntries()
5776   Returns an associative array containing this extension's INI entries and their values */
5777ZEND_METHOD(reflection_extension, getINIEntries)
5778{
5779	reflection_object *intern;
5780	zend_module_entry *module;
5781
5782	if (zend_parse_parameters_none() == FAILURE) {
5783		return;
5784	}
5785	GET_REFLECTION_OBJECT_PTR(module);
5786
5787	array_init(return_value);
5788	zend_hash_apply_with_arguments(EG(ini_directives), (apply_func_args_t) _addinientry, 2, return_value, module->module_number);
5789}
5790/* }}} */
5791
5792/* {{{ add_extension_class */
5793static int add_extension_class(zval *zv, int num_args, va_list args, zend_hash_key *hash_key)
5794{
5795	zend_class_entry *ce = Z_PTR_P(zv);
5796	zval *class_array = va_arg(args, zval*), zclass;
5797	struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
5798	int add_reflection_class = va_arg(args, int);
5799
5800	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
5801		zend_string *name;
5802
5803		if (zend_binary_strcasecmp(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(hash_key->key), ZSTR_LEN(hash_key->key))) {
5804			/* This is an class alias, use alias name */
5805			name = hash_key->key;
5806		} else {
5807			/* Use class name */
5808			name = ce->name;
5809		}
5810		if (add_reflection_class) {
5811			zend_reflection_class_factory(ce, &zclass);
5812			zend_hash_update(Z_ARRVAL_P(class_array), name, &zclass);
5813		} else {
5814			add_next_index_str(class_array, zend_string_copy(name));
5815		}
5816	}
5817	return ZEND_HASH_APPLY_KEEP;
5818}
5819/* }}} */
5820
5821/* {{{ proto public ReflectionClass[] ReflectionExtension::getClasses()
5822   Returns an array containing ReflectionClass objects for all classes of this extension */
5823ZEND_METHOD(reflection_extension, getClasses)
5824{
5825	reflection_object *intern;
5826	zend_module_entry *module;
5827
5828	if (zend_parse_parameters_none() == FAILURE) {
5829		return;
5830	}
5831	GET_REFLECTION_OBJECT_PTR(module);
5832
5833	array_init(return_value);
5834	zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) add_extension_class, 3, return_value, module, 1);
5835}
5836/* }}} */
5837
5838/* {{{ proto public array ReflectionExtension::getClassNames()
5839   Returns an array containing all names of all classes of this extension */
5840ZEND_METHOD(reflection_extension, getClassNames)
5841{
5842	reflection_object *intern;
5843	zend_module_entry *module;
5844
5845	if (zend_parse_parameters_none() == FAILURE) {
5846		return;
5847	}
5848	GET_REFLECTION_OBJECT_PTR(module);
5849
5850	array_init(return_value);
5851	zend_hash_apply_with_arguments(EG(class_table), (apply_func_args_t) add_extension_class, 3, return_value, module, 0);
5852}
5853/* }}} */
5854
5855/* {{{ proto public array ReflectionExtension::getDependencies()
5856   Returns an array containing all names of all extensions this extension depends on */
5857ZEND_METHOD(reflection_extension, getDependencies)
5858{
5859	reflection_object *intern;
5860	zend_module_entry *module;
5861	const zend_module_dep *dep;
5862
5863	if (zend_parse_parameters_none() == FAILURE) {
5864		return;
5865	}
5866	GET_REFLECTION_OBJECT_PTR(module);
5867
5868	dep = module->deps;
5869
5870	if (!dep)
5871	{
5872		ZVAL_EMPTY_ARRAY(return_value);
5873		return;
5874	}
5875
5876	array_init(return_value);
5877	while(dep->name) {
5878		zend_string *relation;
5879		char *rel_type;
5880		size_t len = 0;
5881
5882		switch(dep-&g