xref: /PHP-8.2/ext/reflection/php_reflection.c (revision f8d1864b)
1 /*
2    +----------------------------------------------------------------------+
3    | Copyright (c) The PHP Group                                          |
4    +----------------------------------------------------------------------+
5    | This source file is subject to version 3.01 of the PHP license,      |
6    | that is bundled with this package in the file LICENSE, and is        |
7    | available through the world-wide-web at the following url:           |
8    | https://www.php.net/license/3_01.txt                                 |
9    | If you did not receive a copy of the PHP license and are unable to   |
10    | obtain it through the world-wide-web, please send a note to          |
11    | license@php.net so we can mail you a copy immediately.               |
12    +----------------------------------------------------------------------+
13    | Authors: Timm Friebe <thekid@thekid.de>                              |
14    |          George Schlossnagle <george@omniti.com>                     |
15    |          Andrei Zmievski <andrei@gravitonic.com>                     |
16    |          Marcus Boerger <helly@php.net>                              |
17    |          Johannes Schlueter <johannes@php.net>                       |
18    +----------------------------------------------------------------------+
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "php.h"
26 #include "php_ini.h"
27 #include "php_reflection.h"
28 #include "ext/standard/info.h"
29 #include "ext/standard/sha1.h"
30 #include "ext/random/php_random.h"
31 
32 #include "zend.h"
33 #include "zend_API.h"
34 #include "zend_ast.h"
35 #include "zend_attributes.h"
36 #include "zend_exceptions.h"
37 #include "zend_operators.h"
38 #include "zend_constants.h"
39 #include "zend_ini.h"
40 #include "zend_interfaces.h"
41 #include "zend_closures.h"
42 #include "zend_generators.h"
43 #include "zend_extensions.h"
44 #include "zend_builtin_functions.h"
45 #include "zend_smart_str.h"
46 #include "zend_enum.h"
47 #include "zend_fibers.h"
48 
49 #define REFLECTION_ATTRIBUTE_IS_INSTANCEOF (1 << 1)
50 
51 #include "php_reflection_arginfo.h"
52 
53 /* Key used to avoid leaking addresses in ReflectionProperty::getId() */
54 #define REFLECTION_KEY_LEN 16
55 ZEND_BEGIN_MODULE_GLOBALS(reflection)
56 	bool key_initialized;
57 	unsigned char key[REFLECTION_KEY_LEN];
58 ZEND_END_MODULE_GLOBALS(reflection)
ZEND_DECLARE_MODULE_GLOBALS(reflection)59 ZEND_DECLARE_MODULE_GLOBALS(reflection)
60 
61 #define REFLECTION_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(reflection, v)
62 
63 static zend_always_inline zval *reflection_prop_name(zval *object) {
64 	/* $name is always in the first property slot. */
65 	ZEND_ASSERT(Z_OBJCE_P(object)->default_properties_count >= 1);
66 	return &Z_OBJ_P(object)->properties_table[0];
67 }
68 
reflection_prop_class(zval * object)69 static zend_always_inline zval *reflection_prop_class(zval *object) {
70 	/* $class is always in the second property slot. */
71 	ZEND_ASSERT(Z_OBJCE_P(object)->default_properties_count >= 2);
72 	return &Z_OBJ_P(object)->properties_table[1];
73 }
74 
75 /* Class entry pointers */
76 PHPAPI zend_class_entry *reflector_ptr;
77 PHPAPI zend_class_entry *reflection_exception_ptr;
78 PHPAPI zend_class_entry *reflection_ptr;
79 PHPAPI zend_class_entry *reflection_function_abstract_ptr;
80 PHPAPI zend_class_entry *reflection_function_ptr;
81 PHPAPI zend_class_entry *reflection_generator_ptr;
82 PHPAPI zend_class_entry *reflection_parameter_ptr;
83 PHPAPI zend_class_entry *reflection_type_ptr;
84 PHPAPI zend_class_entry *reflection_named_type_ptr;
85 PHPAPI zend_class_entry *reflection_intersection_type_ptr;
86 PHPAPI zend_class_entry *reflection_union_type_ptr;
87 PHPAPI zend_class_entry *reflection_class_ptr;
88 PHPAPI zend_class_entry *reflection_object_ptr;
89 PHPAPI zend_class_entry *reflection_method_ptr;
90 PHPAPI zend_class_entry *reflection_property_ptr;
91 PHPAPI zend_class_entry *reflection_class_constant_ptr;
92 PHPAPI zend_class_entry *reflection_extension_ptr;
93 PHPAPI zend_class_entry *reflection_zend_extension_ptr;
94 PHPAPI zend_class_entry *reflection_reference_ptr;
95 PHPAPI zend_class_entry *reflection_attribute_ptr;
96 PHPAPI zend_class_entry *reflection_enum_ptr;
97 PHPAPI zend_class_entry *reflection_enum_unit_case_ptr;
98 PHPAPI zend_class_entry *reflection_enum_backed_case_ptr;
99 PHPAPI zend_class_entry *reflection_fiber_ptr;
100 
101 /* Exception throwing macro */
102 #define _DO_THROW(msg) \
103 	zend_throw_exception(reflection_exception_ptr, msg, 0);
104 
105 #define GET_REFLECTION_OBJECT() do { \
106 	intern = Z_REFLECTION_P(ZEND_THIS); \
107 	if (intern->ptr == NULL) { \
108 		if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { \
109 			RETURN_THROWS(); \
110 		} \
111 		zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); \
112 		RETURN_THROWS(); \
113 	} \
114 } while (0)
115 
116 #define GET_REFLECTION_OBJECT_PTR(target) do { \
117 	GET_REFLECTION_OBJECT(); \
118 	target = intern->ptr; \
119 } while (0)
120 
121 /* {{{ Object structure */
122 
123 /* Struct for properties */
124 typedef struct _property_reference {
125 	zend_property_info *prop;
126 	zend_string *unmangled_name;
127 } property_reference;
128 
129 /* Struct for parameters */
130 typedef struct _parameter_reference {
131 	uint32_t offset;
132 	bool required;
133 	struct _zend_arg_info *arg_info;
134 	zend_function *fptr;
135 } parameter_reference;
136 
137 /* Struct for type hints */
138 typedef struct _type_reference {
139 	zend_type type;
140 	/* Whether to use backwards compatible null representation */
141 	bool legacy_behavior;
142 } type_reference;
143 
144 /* Struct for attributes */
145 typedef struct _attribute_reference {
146 	HashTable *attributes;
147 	zend_attribute *data;
148 	zend_class_entry *scope;
149 	zend_string *filename;
150 	uint32_t target;
151 } attribute_reference;
152 
153 typedef enum {
154 	REF_TYPE_OTHER,      /* Must be 0 */
155 	REF_TYPE_FUNCTION,
156 	REF_TYPE_GENERATOR,
157 	REF_TYPE_FIBER,
158 	REF_TYPE_PARAMETER,
159 	REF_TYPE_TYPE,
160 	REF_TYPE_PROPERTY,
161 	REF_TYPE_CLASS_CONSTANT,
162 	REF_TYPE_ATTRIBUTE
163 } reflection_type_t;
164 
165 /* Struct for reflection objects */
166 typedef struct {
167 	zval obj;
168 	void *ptr;
169 	zend_class_entry *ce;
170 	reflection_type_t ref_type;
171 	zend_object zo;
172 } reflection_object;
173 
reflection_object_from_obj(zend_object * obj)174 static inline reflection_object *reflection_object_from_obj(zend_object *obj) {
175 	return (reflection_object*)((char*)(obj) - XtOffsetOf(reflection_object, zo));
176 }
177 
178 #define Z_REFLECTION_P(zv)  reflection_object_from_obj(Z_OBJ_P((zv)))
179 /* }}} */
180 
181 static zend_object_handlers reflection_object_handlers;
182 
prop_get_flags(property_reference * ref)183 static zend_always_inline uint32_t prop_get_flags(property_reference *ref) {
184 	return ref->prop ? ref->prop->flags : ZEND_ACC_PUBLIC;
185 }
186 
is_closure_invoke(zend_class_entry * ce,zend_string * lcname)187 static inline bool is_closure_invoke(zend_class_entry *ce, zend_string *lcname) {
188 	return ce == zend_ce_closure
189 		&& zend_string_equals_literal(lcname, ZEND_INVOKE_FUNC_NAME);
190 }
191 
_copy_function(zend_function * fptr)192 static zend_function *_copy_function(zend_function *fptr) /* {{{ */
193 {
194 	if (fptr
195 		&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
196 	{
197 		zend_function *copy_fptr;
198 		copy_fptr = emalloc(sizeof(zend_function));
199 		memcpy(copy_fptr, fptr, sizeof(zend_function));
200 		copy_fptr->internal_function.function_name = zend_string_copy(fptr->internal_function.function_name);
201 		return copy_fptr;
202 	} else {
203 		/* no copy needed */
204 		return fptr;
205 	}
206 }
207 /* }}} */
208 
_free_function(zend_function * fptr)209 static void _free_function(zend_function *fptr) /* {{{ */
210 {
211 	if (fptr
212 		&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
213 	{
214 		zend_string_release_ex(fptr->internal_function.function_name, 0);
215 		zend_free_trampoline(fptr);
216 	}
217 }
218 /* }}} */
219 
reflection_free_objects_storage(zend_object * object)220 static void reflection_free_objects_storage(zend_object *object) /* {{{ */
221 {
222 	reflection_object *intern = reflection_object_from_obj(object);
223 	parameter_reference *reference;
224 	property_reference *prop_reference;
225 
226 	if (intern->ptr) {
227 		switch (intern->ref_type) {
228 		case REF_TYPE_PARAMETER:
229 			reference = (parameter_reference*)intern->ptr;
230 			_free_function(reference->fptr);
231 			efree(intern->ptr);
232 			break;
233 		case REF_TYPE_TYPE:
234 		{
235 			type_reference *type_ref = intern->ptr;
236 			if (ZEND_TYPE_HAS_NAME(type_ref->type)) {
237 				zend_string_release(ZEND_TYPE_NAME(type_ref->type));
238 			}
239 			efree(type_ref);
240 			break;
241 		}
242 		case REF_TYPE_FUNCTION:
243 			_free_function(intern->ptr);
244 			break;
245 		case REF_TYPE_PROPERTY:
246 			prop_reference = (property_reference*)intern->ptr;
247 			zend_string_release_ex(prop_reference->unmangled_name, 0);
248 			efree(intern->ptr);
249 			break;
250 		case REF_TYPE_ATTRIBUTE: {
251 			attribute_reference *attr_ref = intern->ptr;
252 			if (attr_ref->filename) {
253 				zend_string_release(attr_ref->filename);
254 			}
255 			efree(intern->ptr);
256 			break;
257 		}
258 		case REF_TYPE_GENERATOR:
259 		case REF_TYPE_FIBER:
260 		case REF_TYPE_CLASS_CONSTANT:
261 		case REF_TYPE_OTHER:
262 			break;
263 		}
264 	}
265 	intern->ptr = NULL;
266 	zval_ptr_dtor(&intern->obj);
267 	zend_object_std_dtor(object);
268 }
269 /* }}} */
270 
reflection_get_gc(zend_object * obj,zval ** gc_data,int * gc_data_count)271 static HashTable *reflection_get_gc(zend_object *obj, zval **gc_data, int *gc_data_count) /* {{{ */
272 {
273 	reflection_object *intern = reflection_object_from_obj(obj);
274 	*gc_data = &intern->obj;
275 	*gc_data_count = 1;
276 	return zend_std_get_properties(obj);
277 }
278 /* }}} */
279 
reflection_objects_new(zend_class_entry * class_type)280 static zend_object *reflection_objects_new(zend_class_entry *class_type) /* {{{ */
281 {
282 	reflection_object *intern = zend_object_alloc(sizeof(reflection_object), class_type);
283 
284 	zend_object_std_init(&intern->zo, class_type);
285 	object_properties_init(&intern->zo, class_type);
286 	intern->zo.handlers = &reflection_object_handlers;
287 	return &intern->zo;
288 }
289 /* }}} */
290 
reflection_instantiate(zend_class_entry * pce,zval * object)291 static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
292 {
293 	object_init_ex(object, pce);
294 	return object;
295 }
296 /* }}} */
297 
298 static void _const_string(smart_str *str, char *name, zval *value, char *indent);
299 static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent);
300 static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent);
301 static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char* indent);
302 static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent);
303 static void _extension_string(smart_str *str, zend_module_entry *module, char *indent);
304 static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent);
305 
306 /* {{{ _class_string */
_class_string(smart_str * str,zend_class_entry * ce,zval * obj,char * indent)307 static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent)
308 {
309 	int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
310 	zend_string *sub_indent = strpprintf(0, "%s    ", indent);
311 
312 	/* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
313 	if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) {
314 		smart_str_append_printf(str, "%s%s", indent, ZSTR_VAL(ce->info.user.doc_comment));
315 		smart_str_appendc(str, '\n');
316 	}
317 
318 	if (obj && Z_TYPE_P(obj) == IS_OBJECT) {
319 		smart_str_append_printf(str, "%sObject of class [ ", indent);
320 	} else {
321 		char *kind = "Class";
322 		if (ce->ce_flags & ZEND_ACC_INTERFACE) {
323 			kind = "Interface";
324 		} else if (ce->ce_flags & ZEND_ACC_TRAIT) {
325 			kind = "Trait";
326 		}
327 		smart_str_append_printf(str, "%s%s [ ", indent, kind);
328 	}
329 	smart_str_append_printf(str, (ce->type == ZEND_USER_CLASS) ? "<user" : "<internal");
330 	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module) {
331 		smart_str_append_printf(str, ":%s", ce->info.internal.module->name);
332 	}
333 	smart_str_append_printf(str, "> ");
334 	if (ce->get_iterator != NULL) {
335 		smart_str_append_printf(str, "<iterateable> ");
336 	}
337 	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
338 		smart_str_append_printf(str, "interface ");
339 	} else if (ce->ce_flags & ZEND_ACC_TRAIT) {
340 		smart_str_append_printf(str, "trait ");
341 	} else {
342 		if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
343 			smart_str_append_printf(str, "abstract ");
344 		}
345 		if (ce->ce_flags & ZEND_ACC_FINAL) {
346 			smart_str_append_printf(str, "final ");
347 		}
348 		if (ce->ce_flags & ZEND_ACC_READONLY_CLASS) {
349 			smart_str_append_printf(str, "readonly ");
350 		}
351 		smart_str_append_printf(str, "class ");
352 	}
353 	smart_str_append_printf(str, "%s", ZSTR_VAL(ce->name));
354 	if (ce->parent) {
355 		smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->parent->name));
356 	}
357 
358 	if (ce->num_interfaces) {
359 		uint32_t i;
360 
361 		ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
362 		if (ce->ce_flags & ZEND_ACC_INTERFACE) {
363 			smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->interfaces[0]->name));
364 		} else {
365 			smart_str_append_printf(str, " implements %s", ZSTR_VAL(ce->interfaces[0]->name));
366 		}
367 		for (i = 1; i < ce->num_interfaces; ++i) {
368 			smart_str_append_printf(str, ", %s", ZSTR_VAL(ce->interfaces[i]->name));
369 		}
370 	}
371 	smart_str_append_printf(str, " ] {\n");
372 
373 	/* The information where a class is declared is only available for user classes */
374 	if (ce->type == ZEND_USER_CLASS) {
375 		smart_str_append_printf(str, "%s  @@ %s %d-%d\n", indent, ZSTR_VAL(ce->info.user.filename),
376 						ce->info.user.line_start, ce->info.user.line_end);
377 	}
378 
379 	/* Constants */
380 	smart_str_append_printf(str, "\n");
381 	count = zend_hash_num_elements(&ce->constants_table);
382 	smart_str_append_printf(str, "%s  - Constants [%d] {\n", indent, count);
383 	if (count > 0) {
384 		zend_string *key;
385 		zend_class_constant *c;
386 
387 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, c) {
388 			_class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent));
389 			if (UNEXPECTED(EG(exception))) {
390 				zend_string_release(sub_indent);
391 				return;
392 			}
393 		} ZEND_HASH_FOREACH_END();
394 	}
395 	smart_str_append_printf(str, "%s  }\n", indent);
396 
397 	/* Static properties */
398 	/* counting static properties */
399 	count = zend_hash_num_elements(&ce->properties_info);
400 	if (count > 0) {
401 		zend_property_info *prop;
402 
403 		ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
404 			if ((prop->flags & ZEND_ACC_PRIVATE) && prop->ce != ce) {
405 				count_shadow_props++;
406 			} else if (prop->flags & ZEND_ACC_STATIC) {
407 				count_static_props++;
408 			}
409 		} ZEND_HASH_FOREACH_END();
410 	}
411 
412 	/* static properties */
413 	smart_str_append_printf(str, "\n%s  - Static properties [%d] {\n", indent, count_static_props);
414 	if (count_static_props > 0) {
415 		zend_property_info *prop;
416 
417 		ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
418 			if ((prop->flags & ZEND_ACC_STATIC) && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) {
419 				_property_string(str, prop, NULL, ZSTR_VAL(sub_indent));
420 			}
421 		} ZEND_HASH_FOREACH_END();
422 	}
423 	smart_str_append_printf(str, "%s  }\n", indent);
424 
425 	/* Static methods */
426 	/* counting static methods */
427 	count = zend_hash_num_elements(&ce->function_table);
428 	if (count > 0) {
429 		zend_function *mptr;
430 
431 		ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
432 			if ((mptr->common.fn_flags & ZEND_ACC_STATIC)
433 				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
434 			{
435 				count_static_funcs++;
436 			}
437 		} ZEND_HASH_FOREACH_END();
438 	}
439 
440 	/* static methods */
441 	smart_str_append_printf(str, "\n%s  - Static methods [%d] {", indent, count_static_funcs);
442 	if (count_static_funcs > 0) {
443 		zend_function *mptr;
444 
445 		ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
446 			if ((mptr->common.fn_flags & ZEND_ACC_STATIC)
447 				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
448 			{
449 				smart_str_append_printf(str, "\n");
450 				_function_string(str, mptr, ce, ZSTR_VAL(sub_indent));
451 			}
452 		} ZEND_HASH_FOREACH_END();
453 	} else {
454 		smart_str_append_printf(str, "\n");
455 	}
456 	smart_str_append_printf(str, "%s  }\n", indent);
457 
458 	/* Default/Implicit properties */
459 	count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
460 	smart_str_append_printf(str, "\n%s  - Properties [%d] {\n", indent, count);
461 	if (count > 0) {
462 		zend_property_info *prop;
463 
464 		ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, prop) {
465 			if (!(prop->flags & ZEND_ACC_STATIC)
466 			 && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) {
467 				_property_string(str, prop, NULL, ZSTR_VAL(sub_indent));
468 			}
469 		} ZEND_HASH_FOREACH_END();
470 	}
471 	smart_str_append_printf(str, "%s  }\n", indent);
472 
473 	if (obj && Z_TYPE_P(obj) == IS_OBJECT) {
474 		HashTable    *properties = Z_OBJ_HT_P(obj)->get_properties(Z_OBJ_P(obj));
475 		zend_string  *prop_name;
476 		smart_str prop_str = {0};
477 
478 		count = 0;
479 		if (properties && zend_hash_num_elements(properties)) {
480 			ZEND_HASH_MAP_FOREACH_STR_KEY(properties, prop_name) {
481 				if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */
482 					if (!zend_hash_exists(&ce->properties_info, prop_name)) {
483 						count++;
484 						_property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent));
485 					}
486 				}
487 			} ZEND_HASH_FOREACH_END();
488 		}
489 
490 		smart_str_append_printf(str, "\n%s  - Dynamic properties [%d] {\n", indent, count);
491 		smart_str_append_smart_str(str, &prop_str);
492 		smart_str_append_printf(str, "%s  }\n", indent);
493 		smart_str_free(&prop_str);
494 	}
495 
496 	/* Non static methods */
497 	count = zend_hash_num_elements(&ce->function_table) - count_static_funcs;
498 	if (count > 0) {
499 		zend_function *mptr;
500 		smart_str method_str = {0};
501 
502 		count = 0;
503 		ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
504 			if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0
505 				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
506 			{
507 				zend_function *closure;
508 				/* see if this is a closure */
509 				if (obj && is_closure_invoke(ce, mptr->common.function_name)
510 					&& (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL)
511 				{
512 					mptr = closure;
513 				} else {
514 					closure = NULL;
515 				}
516 				smart_str_appendc(&method_str, '\n');
517 				_function_string(&method_str, mptr, ce, ZSTR_VAL(sub_indent));
518 				count++;
519 				_free_function(closure);
520 			}
521 		} ZEND_HASH_FOREACH_END();
522 		smart_str_append_printf(str, "\n%s  - Methods [%d] {", indent, count);
523 		smart_str_append_smart_str(str, &method_str);
524 		if (!count) {
525 			smart_str_append_printf(str, "\n");
526 		}
527 		smart_str_free(&method_str);
528 	} else {
529 		smart_str_append_printf(str, "\n%s  - Methods [0] {\n", indent);
530 	}
531 	smart_str_append_printf(str, "%s  }\n", indent);
532 
533 	smart_str_append_printf(str, "%s}\n", indent);
534 	zend_string_release_ex(sub_indent, 0);
535 }
536 /* }}} */
537 
538 /* {{{ _const_string */
_const_string(smart_str * str,char * name,zval * value,char * indent)539 static void _const_string(smart_str *str, char *name, zval *value, char *indent)
540 {
541 	const char *type = zend_zval_type_name(value);
542 
543 	if (Z_TYPE_P(value) == IS_ARRAY) {
544 		smart_str_append_printf(str, "%s    Constant [ %s %s ] { Array }\n",
545 						indent, type, name);
546 	} else if (Z_TYPE_P(value) == IS_STRING) {
547 		smart_str_append_printf(str, "%s    Constant [ %s %s ] { %s }\n",
548 						indent, type, name, Z_STRVAL_P(value));
549 	} else {
550 		zend_string *tmp_value_str;
551 		zend_string *value_str = zval_get_tmp_string(value, &tmp_value_str);
552 		smart_str_append_printf(str, "%s    Constant [ %s %s ] { %s }\n",
553 						indent, type, name, ZSTR_VAL(value_str));
554 		zend_tmp_string_release(tmp_value_str);
555 	}
556 }
557 /* }}} */
558 
559 /* {{{ _class_const_string */
_class_const_string(smart_str * str,char * name,zend_class_constant * c,char * indent)560 static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char *indent)
561 {
562 	if (zval_update_constant_ex(&c->value, c->ce) == FAILURE) {
563 		return;
564 	}
565 
566 	const char *visibility = zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c));
567 	const char *final = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_FINAL ? "final " : "";
568 	const char *type = zend_zval_type_name(&c->value);
569 	smart_str_append_printf(str, "%sConstant [ %s%s %s %s ] { ",
570 		indent, final, visibility, type, name);
571 	if (Z_TYPE(c->value) == IS_ARRAY) {
572 		smart_str_appends(str, "Array");
573 	} else if (Z_TYPE(c->value) == IS_OBJECT) {
574 		smart_str_appends(str, "Object");
575 	} else {
576 		zend_string *tmp_value_str;
577 		zend_string *value_str = zval_get_tmp_string(&c->value, &tmp_value_str);
578 		smart_str_append(str, value_str);
579 		zend_tmp_string_release(tmp_value_str);
580 	}
581 	smart_str_appends(str, " }\n");
582 }
583 /* }}} */
584 
get_recv_op(zend_op_array * op_array,uint32_t offset)585 static zend_op *get_recv_op(zend_op_array *op_array, uint32_t offset)
586 {
587 	zend_op *op = op_array->opcodes;
588 	zend_op *end = op + op_array->last;
589 
590 	++offset;
591 	while (op < end) {
592 		if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT
593 		    || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == offset)
594 		{
595 			return op;
596 		}
597 		++op;
598 	}
599 	ZEND_ASSERT(0 && "Failed to find op");
600 	return NULL;
601 }
602 
get_default_from_recv(zend_op_array * op_array,uint32_t offset)603 static zval *get_default_from_recv(zend_op_array *op_array, uint32_t offset) {
604 	zend_op *recv = get_recv_op(op_array, offset);
605 	if (!recv || recv->opcode != ZEND_RECV_INIT) {
606 		return NULL;
607 	}
608 
609 	return RT_CONSTANT(recv, recv->op2);
610 }
611 
format_default_value(smart_str * str,zval * value)612 static int format_default_value(smart_str *str, zval *value) {
613 	if (Z_TYPE_P(value) <= IS_STRING) {
614 		smart_str_append_scalar(str, value, SIZE_MAX);
615 	} else if (Z_TYPE_P(value) == IS_ARRAY) {
616 		zend_string *str_key;
617 		zend_long num_key;
618 		zval *zv;
619 		bool is_list = zend_array_is_list(Z_ARRVAL_P(value));
620 		bool first = true;
621 		smart_str_appendc(str, '[');
622 		ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(value), num_key, str_key, zv) {
623 			if (!first) {
624 				smart_str_appends(str, ", ");
625 			}
626 			first = false;
627 
628 			if (!is_list) {
629 				if (str_key) {
630 					smart_str_appendc(str, '\'');
631 					smart_str_append_escaped(str, ZSTR_VAL(str_key), ZSTR_LEN(str_key));
632 					smart_str_appendc(str, '\'');
633 				} else {
634 					smart_str_append_long(str, num_key);
635 				}
636 				smart_str_appends(str, " => ");
637 			}
638 			format_default_value(str, zv);
639 		} ZEND_HASH_FOREACH_END();
640 		smart_str_appendc(str, ']');
641 	} else if (Z_TYPE_P(value) == IS_OBJECT) {
642 		/* This branch may only be reached for default properties, which don't support arbitrary objects. */
643 		zend_object *obj = Z_OBJ_P(value);
644 		zend_class_entry *class = obj->ce;
645 		ZEND_ASSERT(class->ce_flags & ZEND_ACC_ENUM);
646 		smart_str_append(str, class->name);
647 		smart_str_appends(str, "::");
648 		smart_str_append(str, Z_STR_P(zend_enum_fetch_case_name(obj)));
649 	} else {
650 		ZEND_ASSERT(Z_TYPE_P(value) == IS_CONSTANT_AST);
651 		zend_string *ast_str = zend_ast_export("", Z_ASTVAL_P(value), "");
652 		smart_str_append(str, ast_str);
653 		zend_string_release(ast_str);
654 	}
655 	return SUCCESS;
656 }
657 
has_internal_arg_info(const zend_function * fptr)658 static inline bool has_internal_arg_info(const zend_function *fptr) {
659 	return fptr->type == ZEND_INTERNAL_FUNCTION
660 		&& !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO);
661 }
662 
663 /* {{{ _parameter_string */
_parameter_string(smart_str * str,zend_function * fptr,struct _zend_arg_info * arg_info,uint32_t offset,bool required,char * indent)664 static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_arg_info *arg_info, uint32_t offset, bool required, char* indent)
665 {
666 	smart_str_append_printf(str, "Parameter #%d [ ", offset);
667 	if (!required) {
668 		smart_str_append_printf(str, "<optional> ");
669 	} else {
670 		smart_str_append_printf(str, "<required> ");
671 	}
672 	if (ZEND_TYPE_IS_SET(arg_info->type)) {
673 		zend_string *type_str = zend_type_to_string(arg_info->type);
674 		smart_str_append(str, type_str);
675 		smart_str_appendc(str, ' ');
676 		zend_string_release(type_str);
677 	}
678 	if (ZEND_ARG_SEND_MODE(arg_info)) {
679 		smart_str_appendc(str, '&');
680 	}
681 	if (ZEND_ARG_IS_VARIADIC(arg_info)) {
682 		smart_str_appends(str, "...");
683 	}
684 	smart_str_append_printf(str, "$%s", has_internal_arg_info(fptr)
685 		? ((zend_internal_arg_info*)arg_info)->name : ZSTR_VAL(arg_info->name));
686 
687 	if (!required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
688 		if (fptr->type == ZEND_INTERNAL_FUNCTION) {
689 			smart_str_appends(str, " = ");
690 			/* TODO: We don't have a way to fetch the default value for an internal function
691 			 * with userland arg info. */
692 			if (has_internal_arg_info(fptr)
693 					&& ((zend_internal_arg_info*)arg_info)->default_value) {
694 				smart_str_appends(str, ((zend_internal_arg_info*)arg_info)->default_value);
695 			} else {
696 				smart_str_appends(str, "<default>");
697 			}
698 		} else {
699 			zval *default_value = get_default_from_recv((zend_op_array*)fptr, offset);
700 			if (default_value) {
701 				smart_str_appends(str, " = ");
702 				if (format_default_value(str, default_value) == FAILURE) {
703 					return;
704 				}
705 			}
706 		}
707 	}
708 	smart_str_appends(str, " ]");
709 }
710 /* }}} */
711 
712 /* {{{ _function_parameter_string */
_function_parameter_string(smart_str * str,zend_function * fptr,char * indent)713 static void _function_parameter_string(smart_str *str, zend_function *fptr, char* indent)
714 {
715 	struct _zend_arg_info *arg_info = fptr->common.arg_info;
716 	uint32_t i, num_args, num_required = fptr->common.required_num_args;
717 
718 	if (!arg_info) {
719 		return;
720 	}
721 
722 	num_args = fptr->common.num_args;
723 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
724 		num_args++;
725 	}
726 	smart_str_appendc(str, '\n');
727 	smart_str_append_printf(str, "%s- Parameters [%d] {\n", indent, num_args);
728 	for (i = 0; i < num_args; i++) {
729 		smart_str_append_printf(str, "%s  ", indent);
730 		_parameter_string(str, fptr, arg_info, i, i < num_required, indent);
731 		smart_str_appendc(str, '\n');
732 		arg_info++;
733 	}
734 	smart_str_append_printf(str, "%s}\n", indent);
735 }
736 /* }}} */
737 
738 /* {{{ _function_closure_string */
_function_closure_string(smart_str * str,zend_function * fptr,char * indent)739 static void _function_closure_string(smart_str *str, zend_function *fptr, char* indent)
740 {
741 	uint32_t i, count;
742 	zend_string *key;
743 	HashTable *static_variables;
744 
745 	if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) {
746 		return;
747 	}
748 
749 	static_variables = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
750 	count = zend_hash_num_elements(static_variables);
751 
752 	if (!count) {
753 		return;
754 	}
755 
756 	smart_str_append_printf(str, "\n");
757 	smart_str_append_printf(str, "%s- Bound Variables [%d] {\n", indent, zend_hash_num_elements(static_variables));
758 	i = 0;
759 	ZEND_HASH_MAP_FOREACH_STR_KEY(static_variables, key) {
760 		smart_str_append_printf(str, "%s    Variable #%d [ $%s ]\n", indent, i++, ZSTR_VAL(key));
761 	} ZEND_HASH_FOREACH_END();
762 	smart_str_append_printf(str, "%s}\n", indent);
763 }
764 /* }}} */
765 
766 /* {{{ _function_string */
_function_string(smart_str * str,zend_function * fptr,zend_class_entry * scope,char * indent)767 static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent)
768 {
769 	smart_str param_indent = {0};
770 	zend_function *overwrites;
771 	zend_string *lc_name;
772 
773 	/* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
774 	 * What's "wrong" is that any whitespace before the doc comment start is
775 	 * swallowed, leading to an unaligned comment.
776 	 */
777 	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
778 		smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->op_array.doc_comment));
779 	}
780 
781 	smart_str_appendl(str, indent, strlen(indent));
782 	smart_str_append_printf(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ "));
783 	smart_str_append_printf(str, (fptr->type == ZEND_USER_FUNCTION) ? "<user" : "<internal");
784 	if (fptr->common.fn_flags & ZEND_ACC_DEPRECATED) {
785 		smart_str_appends(str, ", deprecated");
786 	}
787 	if (fptr->type == ZEND_INTERNAL_FUNCTION && ((zend_internal_function*)fptr)->module) {
788 		smart_str_append_printf(str, ":%s", ((zend_internal_function*)fptr)->module->name);
789 	}
790 
791 	if (scope && fptr->common.scope) {
792 		if (fptr->common.scope != scope) {
793 			smart_str_append_printf(str, ", inherits %s", ZSTR_VAL(fptr->common.scope->name));
794 		} else if (fptr->common.scope->parent) {
795 			lc_name = zend_string_tolower(fptr->common.function_name);
796 			if ((overwrites = zend_hash_find_ptr(&fptr->common.scope->parent->function_table, lc_name)) != NULL) {
797 				if (fptr->common.scope != overwrites->common.scope && !(overwrites->common.fn_flags & ZEND_ACC_PRIVATE)) {
798 					smart_str_append_printf(str, ", overwrites %s", ZSTR_VAL(overwrites->common.scope->name));
799 				}
800 			}
801 			zend_string_release_ex(lc_name, 0);
802 		}
803 	}
804 	if (fptr->common.prototype && fptr->common.prototype->common.scope) {
805 		smart_str_append_printf(str, ", prototype %s", ZSTR_VAL(fptr->common.prototype->common.scope->name));
806 	}
807 	if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
808 		smart_str_appends(str, ", ctor");
809 	}
810 	smart_str_appends(str, "> ");
811 
812 	if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
813 		smart_str_appends(str, "abstract ");
814 	}
815 	if (fptr->common.fn_flags & ZEND_ACC_FINAL) {
816 		smart_str_appends(str, "final ");
817 	}
818 	if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
819 		smart_str_appends(str, "static ");
820 	}
821 
822 	if (fptr->common.scope) {
823 		/* These are mutually exclusive */
824 		switch (fptr->common.fn_flags & ZEND_ACC_PPP_MASK) {
825 			case ZEND_ACC_PUBLIC:
826 				smart_str_appends(str, "public ");
827 				break;
828 			case ZEND_ACC_PRIVATE:
829 				smart_str_appends(str, "private ");
830 				break;
831 			case ZEND_ACC_PROTECTED:
832 				smart_str_appends(str, "protected ");
833 				break;
834 			default:
835 				smart_str_appends(str, "<visibility error> ");
836 				break;
837 		}
838 		smart_str_appends(str, "method ");
839 	} else {
840 		smart_str_appends(str, "function ");
841 	}
842 
843 	if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
844 		smart_str_appendc(str, '&');
845 	}
846 	smart_str_append_printf(str, "%s ] {\n", ZSTR_VAL(fptr->common.function_name));
847 	/* The information where a function is declared is only available for user classes */
848 	if (fptr->type == ZEND_USER_FUNCTION) {
849 		smart_str_append_printf(str, "%s  @@ %s %d - %d\n", indent,
850 						ZSTR_VAL(fptr->op_array.filename),
851 						fptr->op_array.line_start,
852 						fptr->op_array.line_end);
853 	}
854 	smart_str_append_printf(&param_indent, "%s  ", indent);
855 	smart_str_0(&param_indent);
856 	if (fptr->common.fn_flags & ZEND_ACC_CLOSURE) {
857 		_function_closure_string(str, fptr, ZSTR_VAL(param_indent.s));
858 	}
859 	_function_parameter_string(str, fptr, ZSTR_VAL(param_indent.s));
860 	smart_str_free(&param_indent);
861 	if ((fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
862 		smart_str_append_printf(str, "  %s- %s [ ", indent, ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]) ? "Tentative return" : "Return");
863 		if (ZEND_TYPE_IS_SET(fptr->common.arg_info[-1].type)) {
864 			zend_string *type_str = zend_type_to_string(fptr->common.arg_info[-1].type);
865 			smart_str_append_printf(str, "%s ", ZSTR_VAL(type_str));
866 			zend_string_release(type_str);
867 		}
868 		smart_str_appends(str, "]\n");
869 	}
870 	smart_str_append_printf(str, "%s}\n", indent);
871 }
872 /* }}} */
873 
property_get_default(zend_property_info * prop_info)874 static zval *property_get_default(zend_property_info *prop_info) {
875 	zend_class_entry *ce = prop_info->ce;
876 	if (prop_info->flags & ZEND_ACC_STATIC) {
877 		zval *prop = &ce->default_static_members_table[prop_info->offset];
878 		ZVAL_DEINDIRECT(prop);
879 		return prop;
880 	} else {
881 		return &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
882 	}
883 }
884 
885 /* {{{ _property_string */
_property_string(smart_str * str,zend_property_info * prop,const char * prop_name,char * indent)886 static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent)
887 {
888 	smart_str_append_printf(str, "%sProperty [ ", indent);
889 	if (!prop) {
890 		smart_str_append_printf(str, "<dynamic> public $%s", prop_name);
891 	} else {
892 		/* These are mutually exclusive */
893 		switch (prop->flags & ZEND_ACC_PPP_MASK) {
894 			case ZEND_ACC_PUBLIC:
895 				smart_str_appends(str, "public ");
896 				break;
897 			case ZEND_ACC_PRIVATE:
898 				smart_str_appends(str, "private ");
899 				break;
900 			case ZEND_ACC_PROTECTED:
901 				smart_str_appends(str, "protected ");
902 				break;
903 		}
904 		if (prop->flags & ZEND_ACC_STATIC) {
905 			smart_str_appends(str, "static ");
906 		}
907 		if (prop->flags & ZEND_ACC_READONLY) {
908 			smart_str_appends(str, "readonly ");
909 		}
910 		if (ZEND_TYPE_IS_SET(prop->type)) {
911 			zend_string *type_str = zend_type_to_string(prop->type);
912 			smart_str_append(str, type_str);
913 			smart_str_appendc(str, ' ');
914 			zend_string_release(type_str);
915 		}
916 		if (!prop_name) {
917 			const char *class_name;
918 			zend_unmangle_property_name(prop->name, &class_name, &prop_name);
919 		}
920 		smart_str_append_printf(str, "$%s", prop_name);
921 
922 		zval *default_value = property_get_default(prop);
923 		if (!Z_ISUNDEF_P(default_value)) {
924 			smart_str_appends(str, " = ");
925 			if (format_default_value(str, default_value) == FAILURE) {
926 				return;
927 			}
928 		}
929 	}
930 
931 	smart_str_appends(str, " ]\n");
932 }
933 /* }}} */
934 
_extension_ini_string(zend_ini_entry * ini_entry,smart_str * str,char * indent,int number)935 static void _extension_ini_string(zend_ini_entry *ini_entry, smart_str *str, char *indent, int number) /* {{{ */
936 {
937 	char *comma = "";
938 
939 	if (number == ini_entry->module_number) {
940 		smart_str_append_printf(str, "    %sEntry [ %s <", indent, ZSTR_VAL(ini_entry->name));
941 		if (ini_entry->modifiable == ZEND_INI_ALL) {
942 			smart_str_appends(str, "ALL");
943 		} else {
944 			if (ini_entry->modifiable & ZEND_INI_USER) {
945 				smart_str_appends(str, "USER");
946 				comma = ",";
947 			}
948 			if (ini_entry->modifiable & ZEND_INI_PERDIR) {
949 				smart_str_append_printf(str, "%sPERDIR", comma);
950 				comma = ",";
951 			}
952 			if (ini_entry->modifiable & ZEND_INI_SYSTEM) {
953 				smart_str_append_printf(str, "%sSYSTEM", comma);
954 			}
955 		}
956 
957 		smart_str_appends(str, "> ]\n");
958 		smart_str_append_printf(str, "    %s  Current = '%s'\n", indent, ini_entry->value ? ZSTR_VAL(ini_entry->value) : "");
959 		if (ini_entry->modified) {
960 			smart_str_append_printf(str, "    %s  Default = '%s'\n", indent, ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : "");
961 		}
962 		smart_str_append_printf(str, "    %s}\n", indent);
963 	}
964 }
965 /* }}} */
966 
_extension_class_string(zend_class_entry * ce,zend_string * key,smart_str * str,char * indent,zend_module_entry * module,int * num_classes)967 static void _extension_class_string(zend_class_entry *ce, zend_string *key, smart_str *str, char *indent, zend_module_entry *module, int *num_classes) /* {{{ */
968 {
969 	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
970 		/* dump class if it is not an alias */
971 		if (zend_string_equals_ci(ce->name, key)) {
972 			smart_str_append_printf(str, "\n");
973 			_class_string(str, ce, NULL, indent);
974 			(*num_classes)++;
975 		}
976 	}
977 }
978 /* }}} */
979 
_extension_string(smart_str * str,zend_module_entry * module,char * indent)980 static void _extension_string(smart_str *str, zend_module_entry *module, char *indent) /* {{{ */
981 {
982 	smart_str_append_printf(str, "%sExtension [ ", indent);
983 	if (module->type == MODULE_PERSISTENT) {
984 		smart_str_appends(str, "<persistent>");
985 	}
986 	if (module->type == MODULE_TEMPORARY) {
987 		smart_str_appends(str, "<temporary>" );
988 	}
989 	smart_str_append_printf(str, " extension #%d %s version %s ] {\n",
990 					module->module_number, module->name,
991 					(module->version == NO_VERSION_YET) ? "<no_version>" : module->version);
992 
993 	if (module->deps) {
994 		const zend_module_dep* dep = module->deps;
995 
996 		smart_str_appends(str, "\n  - Dependencies {\n");
997 
998 		while(dep->name) {
999 			smart_str_append_printf(str, "%s    Dependency [ %s (", indent, dep->name);
1000 
1001 			switch(dep->type) {
1002 			case MODULE_DEP_REQUIRED:
1003 				smart_str_appends(str, "Required");
1004 				break;
1005 			case MODULE_DEP_CONFLICTS:
1006 				smart_str_appends(str, "Conflicts");
1007 				break;
1008 			case MODULE_DEP_OPTIONAL:
1009 				smart_str_appends(str, "Optional");
1010 				break;
1011 			default:
1012 				smart_str_appends(str, "Error"); /* shouldn't happen */
1013 				break;
1014 			}
1015 
1016 			if (dep->rel) {
1017 				smart_str_append_printf(str, " %s", dep->rel);
1018 			}
1019 			if (dep->version) {
1020 				smart_str_append_printf(str, " %s", dep->version);
1021 			}
1022 			smart_str_appends(str, ") ]\n");
1023 			dep++;
1024 		}
1025 		smart_str_append_printf(str, "%s  }\n", indent);
1026 	}
1027 
1028 	{
1029 		smart_str str_ini = {0};
1030 		zend_ini_entry *ini_entry;
1031 		ZEND_HASH_MAP_FOREACH_PTR(EG(ini_directives), ini_entry) {
1032 			_extension_ini_string(ini_entry, &str_ini, indent, module->module_number);
1033 		} ZEND_HASH_FOREACH_END();
1034 		if (smart_str_get_len(&str_ini) > 0) {
1035 			smart_str_append_printf(str, "\n  - INI {\n");
1036 			smart_str_append_smart_str(str, &str_ini);
1037 			smart_str_append_printf(str, "%s  }\n", indent);
1038 		}
1039 		smart_str_free(&str_ini);
1040 	}
1041 
1042 	{
1043 		smart_str str_constants = {0};
1044 		zend_constant *constant;
1045 		int num_constants = 0;
1046 
1047 		ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
1048 			if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) {
1049 				_const_string(&str_constants, ZSTR_VAL(constant->name), &constant->value, indent);
1050 				num_constants++;
1051 			}
1052 		} ZEND_HASH_FOREACH_END();
1053 
1054 		if (num_constants) {
1055 			smart_str_append_printf(str, "\n  - Constants [%d] {\n", num_constants);
1056 			smart_str_append_smart_str(str, &str_constants);
1057 			smart_str_append_printf(str, "%s  }\n", indent);
1058 		}
1059 		smart_str_free(&str_constants);
1060 	}
1061 
1062 	{
1063 		zend_function *fptr;
1064 		int first = 1;
1065 
1066 		ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), fptr) {
1067 			if (fptr->common.type==ZEND_INTERNAL_FUNCTION
1068 				&& fptr->internal_function.module == module) {
1069 				if (first) {
1070 					smart_str_append_printf(str, "\n  - Functions {\n");
1071 					first = 0;
1072 				}
1073 				_function_string(str, fptr, NULL, "    ");
1074 			}
1075 		} ZEND_HASH_FOREACH_END();
1076 		if (!first) {
1077 			smart_str_append_printf(str, "%s  }\n", indent);
1078 		}
1079 	}
1080 
1081 	{
1082 		zend_string *sub_indent = strpprintf(0, "%s    ", indent);
1083 		smart_str str_classes = {0};
1084 		zend_string *key;
1085 		zend_class_entry *ce;
1086 		int num_classes = 0;
1087 
1088 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
1089 			_extension_class_string(ce, key, &str_classes, ZSTR_VAL(sub_indent), module, &num_classes);
1090 		} ZEND_HASH_FOREACH_END();
1091 		if (num_classes) {
1092 			smart_str_append_printf(str, "\n  - Classes [%d] {", num_classes);
1093 			smart_str_append_smart_str(str, &str_classes);
1094 			smart_str_append_printf(str, "%s  }\n", indent);
1095 		}
1096 		smart_str_free(&str_classes);
1097 		zend_string_release_ex(sub_indent, 0);
1098 	}
1099 
1100 	smart_str_append_printf(str, "%s}\n", indent);
1101 }
1102 /* }}} */
1103 
1104 /* {{{ reflection_attribute_factory */
reflection_attribute_factory(zval * object,HashTable * attributes,zend_attribute * data,zend_class_entry * scope,uint32_t target,zend_string * filename)1105 static void reflection_attribute_factory(zval *object, HashTable *attributes, zend_attribute *data,
1106 		zend_class_entry *scope, uint32_t target, zend_string *filename)
1107 {
1108 	reflection_object *intern;
1109 	attribute_reference *reference;
1110 
1111 	reflection_instantiate(reflection_attribute_ptr, object);
1112 	intern  = Z_REFLECTION_P(object);
1113 	reference = (attribute_reference*) emalloc(sizeof(attribute_reference));
1114 	reference->attributes = attributes;
1115 	reference->data = data;
1116 	reference->scope = scope;
1117 	reference->filename = filename ? zend_string_copy(filename) : NULL;
1118 	reference->target = target;
1119 	intern->ptr = reference;
1120 	intern->ref_type = REF_TYPE_ATTRIBUTE;
1121 }
1122 /* }}} */
1123 
read_attributes(zval * ret,HashTable * attributes,zend_class_entry * scope,uint32_t offset,uint32_t target,zend_string * name,zend_class_entry * base,zend_string * filename)1124 static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope,
1125 		uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename) /* {{{ */
1126 {
1127 	ZEND_ASSERT(attributes != NULL);
1128 
1129 	zend_attribute *attr;
1130 	zval tmp;
1131 
1132 	if (name) {
1133 		// Name based filtering using lowercased key.
1134 		zend_string *filter = zend_string_tolower(name);
1135 
1136 		ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
1137 			if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) {
1138 				reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1139 				add_next_index_zval(ret, &tmp);
1140 			}
1141 		} ZEND_HASH_FOREACH_END();
1142 
1143 		zend_string_release(filter);
1144 		return SUCCESS;
1145 	}
1146 
1147 	ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
1148 		if (attr->offset != offset) {
1149 			continue;
1150 		}
1151 
1152 		if (base) {
1153 			// Base type filtering.
1154 			zend_class_entry *ce = zend_lookup_class_ex(attr->name, attr->lcname, 0);
1155 
1156 			if (ce == NULL) {
1157 				// Bailout on error, otherwise ignore unavailable class.
1158 				if (EG(exception)) {
1159 					return FAILURE;
1160 				}
1161 
1162 				continue;
1163 			}
1164 
1165 			if (!instanceof_function(ce, base)) {
1166 				continue;
1167 			}
1168 		}
1169 
1170 		reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1171 		add_next_index_zval(ret, &tmp);
1172 	} ZEND_HASH_FOREACH_END();
1173 
1174 	return SUCCESS;
1175 }
1176 /* }}} */
1177 
reflect_attributes(INTERNAL_FUNCTION_PARAMETERS,HashTable * attributes,uint32_t offset,zend_class_entry * scope,uint32_t target,zend_string * filename)1178 static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes,
1179 		uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */
1180 {
1181 	zend_string *name = NULL;
1182 	zend_long flags = 0;
1183 	zend_class_entry *base = NULL;
1184 
1185 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!l", &name, &flags) == FAILURE) {
1186 		RETURN_THROWS();
1187 	}
1188 
1189 	if (flags & ~REFLECTION_ATTRIBUTE_IS_INSTANCEOF) {
1190 		zend_argument_value_error(2, "must be a valid attribute filter flag");
1191 		RETURN_THROWS();
1192 	}
1193 
1194 	if (name && (flags & REFLECTION_ATTRIBUTE_IS_INSTANCEOF)) {
1195 		if (NULL == (base = zend_lookup_class(name))) {
1196 			if (!EG(exception)) {
1197 				zend_throw_error(NULL, "Class \"%s\" not found", ZSTR_VAL(name));
1198 			}
1199 
1200 			RETURN_THROWS();
1201 		}
1202 
1203 		name = NULL;
1204 	}
1205 
1206 	if (!attributes) {
1207 		RETURN_EMPTY_ARRAY();
1208 	}
1209 
1210 	array_init(return_value);
1211 
1212 	if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) {
1213 		RETURN_THROWS();
1214 	}
1215 }
1216 /* }}} */
1217 
_zend_extension_string(smart_str * str,zend_extension * extension,char * indent)1218 static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent) /* {{{ */
1219 {
1220 	smart_str_append_printf(str, "%sZend Extension [ %s ", indent, extension->name);
1221 
1222 	if (extension->version) {
1223 		smart_str_append_printf(str, "%s ", extension->version);
1224 	}
1225 	if (extension->copyright) {
1226 		smart_str_append_printf(str, "%s ", extension->copyright);
1227 	}
1228 	if (extension->author) {
1229 		smart_str_append_printf(str, "by %s ", extension->author);
1230 	}
1231 	if (extension->URL) {
1232 		smart_str_append_printf(str, "<%s> ", extension->URL);
1233 	}
1234 
1235 	smart_str_appends(str, "]\n");
1236 }
1237 /* }}} */
1238 
1239 /* {{{ _function_check_flag */
_function_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)1240 static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
1241 {
1242 	reflection_object *intern;
1243 	zend_function *mptr;
1244 
1245 	if (zend_parse_parameters_none() == FAILURE) {
1246 		RETURN_THROWS();
1247 	}
1248 	GET_REFLECTION_OBJECT_PTR(mptr);
1249 	RETURN_BOOL(mptr->common.fn_flags & mask);
1250 }
1251 /* }}} */
1252 
1253 /* {{{ zend_reflection_class_factory */
zend_reflection_class_factory(zend_class_entry * ce,zval * object)1254 PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object)
1255 {
1256 	reflection_object *intern;
1257 
1258 	zend_class_entry *reflection_ce =
1259 		ce->ce_flags & ZEND_ACC_ENUM ? reflection_enum_ptr : reflection_class_ptr;
1260 	reflection_instantiate(reflection_ce, object);
1261 	intern = Z_REFLECTION_P(object);
1262 	intern->ptr = ce;
1263 	intern->ref_type = REF_TYPE_OTHER;
1264 	intern->ce = ce;
1265 	ZVAL_STR_COPY(reflection_prop_name(object), ce->name);
1266 }
1267 /* }}} */
1268 
1269 /* {{{ reflection_extension_factory */
reflection_extension_factory(zval * object,const char * name_str)1270 static void reflection_extension_factory(zval *object, const char *name_str)
1271 {
1272 	reflection_object *intern;
1273 	size_t name_len = strlen(name_str);
1274 	zend_string *lcname;
1275 	struct _zend_module_entry *module;
1276 
1277 	lcname = zend_string_alloc(name_len, 0);
1278 	zend_str_tolower_copy(ZSTR_VAL(lcname), name_str, name_len);
1279 	module = zend_hash_find_ptr(&module_registry, lcname);
1280 	zend_string_efree(lcname);
1281 	if (!module) {
1282 		return;
1283 	}
1284 
1285 	reflection_instantiate(reflection_extension_ptr, object);
1286 	intern = Z_REFLECTION_P(object);
1287 	intern->ptr = module;
1288 	intern->ref_type = REF_TYPE_OTHER;
1289 	intern->ce = NULL;
1290 	ZVAL_STRINGL(reflection_prop_name(object), module->name, name_len);
1291 }
1292 /* }}} */
1293 
1294 /* {{{ reflection_parameter_factory */
reflection_parameter_factory(zend_function * fptr,zval * closure_object,struct _zend_arg_info * arg_info,uint32_t offset,bool required,zval * object)1295 static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, uint32_t offset, bool required, zval *object)
1296 {
1297 	reflection_object *intern;
1298 	parameter_reference *reference;
1299 	zval *prop_name;
1300 
1301 	reflection_instantiate(reflection_parameter_ptr, object);
1302 	intern = Z_REFLECTION_P(object);
1303 	reference = (parameter_reference*) emalloc(sizeof(parameter_reference));
1304 	reference->arg_info = arg_info;
1305 	reference->offset = offset;
1306 	reference->required = required;
1307 	reference->fptr = fptr;
1308 	intern->ptr = reference;
1309 	intern->ref_type = REF_TYPE_PARAMETER;
1310 	intern->ce = fptr->common.scope;
1311 	if (closure_object) {
1312 		ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object));
1313 	}
1314 
1315 	prop_name = reflection_prop_name(object);
1316 	if (has_internal_arg_info(fptr)) {
1317 		ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)->name);
1318 	} else {
1319 		ZVAL_STR_COPY(prop_name, arg_info->name);
1320 	}
1321 }
1322 /* }}} */
1323 
1324 typedef enum {
1325 	NAMED_TYPE = 0,
1326 	UNION_TYPE = 1,
1327 	INTERSECTION_TYPE = 2
1328 } reflection_type_kind;
1329 
1330 /* For backwards compatibility reasons, we need to return T|null style unions
1331  * and transformation from iterable to Traversable|array
1332  * as a ReflectionNamedType. Here we determine what counts as a union type and
1333  * what doesn't. */
get_type_kind(zend_type type)1334 static reflection_type_kind get_type_kind(zend_type type) {
1335 	uint32_t type_mask_without_null = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(type);
1336 
1337 	if (ZEND_TYPE_HAS_LIST(type)) {
1338 		if (ZEND_TYPE_IS_INTERSECTION(type)) {
1339 			return INTERSECTION_TYPE;
1340 		}
1341 		ZEND_ASSERT(ZEND_TYPE_IS_UNION(type));
1342 		return UNION_TYPE;
1343 	}
1344 
1345 	if (ZEND_TYPE_IS_COMPLEX(type)) {
1346 		/* BC support for 'iterable' type */
1347 		if (UNEXPECTED(ZEND_TYPE_IS_ITERABLE_FALLBACK(type))) {
1348 			return NAMED_TYPE;
1349 		}
1350 		if (type_mask_without_null != 0) {
1351 			return UNION_TYPE;
1352 		}
1353 		return NAMED_TYPE;
1354 	}
1355 	if (type_mask_without_null == MAY_BE_BOOL || ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY) {
1356 		return NAMED_TYPE;
1357 	}
1358 	/* Check that only one bit is set. */
1359 	if ((type_mask_without_null & (type_mask_without_null - 1)) != 0) {
1360 		return UNION_TYPE;
1361 	}
1362 	return NAMED_TYPE;
1363 }
1364 
1365 /* {{{ reflection_type_factory */
reflection_type_factory(zend_type type,zval * object,bool legacy_behavior)1366 static void reflection_type_factory(zend_type type, zval *object, bool legacy_behavior)
1367 {
1368 	reflection_object *intern;
1369 	type_reference *reference;
1370 	reflection_type_kind type_kind = get_type_kind(type);
1371 	bool is_mixed = ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY;
1372 	bool is_only_null = (ZEND_TYPE_PURE_MASK(type) == MAY_BE_NULL && !ZEND_TYPE_IS_COMPLEX(type));
1373 
1374 	switch (type_kind) {
1375 		case INTERSECTION_TYPE:
1376 			reflection_instantiate(reflection_intersection_type_ptr, object);
1377 			break;
1378 		case UNION_TYPE:
1379 			reflection_instantiate(reflection_union_type_ptr, object);
1380 			break;
1381 		case NAMED_TYPE:
1382 			reflection_instantiate(reflection_named_type_ptr, object);
1383 			break;
1384 		EMPTY_SWITCH_DEFAULT_CASE();
1385 	}
1386 
1387 	intern = Z_REFLECTION_P(object);
1388 	reference = (type_reference*) emalloc(sizeof(type_reference));
1389 	reference->type = type;
1390 	reference->legacy_behavior = legacy_behavior && type_kind == NAMED_TYPE && !is_mixed && !is_only_null;
1391 	intern->ptr = reference;
1392 	intern->ref_type = REF_TYPE_TYPE;
1393 
1394 	/* Property types may be resolved during the lifetime of the ReflectionType.
1395 	 * If we reference a string, make sure it doesn't get released. However, only
1396 	 * do this for the top-level type, as resolutions inside type lists will be
1397 	 * fully visible to us (we'd have to do a fully copy of the type if we wanted
1398 	 * to prevent that). */
1399 	if (ZEND_TYPE_HAS_NAME(type)) {
1400 		zend_string_addref(ZEND_TYPE_NAME(type));
1401 	}
1402 }
1403 /* }}} */
1404 
1405 /* {{{ reflection_function_factory */
reflection_function_factory(zend_function * function,zval * closure_object,zval * object)1406 static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object)
1407 {
1408 	reflection_object *intern;
1409 	reflection_instantiate(reflection_function_ptr, object);
1410 	intern = Z_REFLECTION_P(object);
1411 	intern->ptr = function;
1412 	intern->ref_type = REF_TYPE_FUNCTION;
1413 	intern->ce = NULL;
1414 	if (closure_object) {
1415 		ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object));
1416 	}
1417 	ZVAL_STR_COPY(reflection_prop_name(object), function->common.function_name);
1418 }
1419 /* }}} */
1420 
1421 /* {{{ reflection_method_factory */
reflection_method_factory(zend_class_entry * ce,zend_function * method,zval * closure_object,zval * object)1422 static void reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object)
1423 {
1424 	reflection_object *intern;
1425 
1426 	reflection_instantiate(reflection_method_ptr, object);
1427 	intern = Z_REFLECTION_P(object);
1428 	intern->ptr = method;
1429 	intern->ref_type = REF_TYPE_FUNCTION;
1430 	intern->ce = ce;
1431 	if (closure_object) {
1432 		ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object));
1433 	}
1434 
1435 	ZVAL_STR_COPY(reflection_prop_name(object), method->common.function_name);
1436 	ZVAL_STR_COPY(reflection_prop_class(object), method->common.scope->name);
1437 }
1438 /* }}} */
1439 
1440 /* {{{ reflection_property_factory */
reflection_property_factory(zend_class_entry * ce,zend_string * name,zend_property_info * prop,zval * object)1441 static void reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object)
1442 {
1443 	reflection_object *intern;
1444 	property_reference *reference;
1445 
1446 	reflection_instantiate(reflection_property_ptr, object);
1447 	intern = Z_REFLECTION_P(object);
1448 	reference = (property_reference*) emalloc(sizeof(property_reference));
1449 	reference->prop = prop;
1450 	reference->unmangled_name = zend_string_copy(name);
1451 	intern->ptr = reference;
1452 	intern->ref_type = REF_TYPE_PROPERTY;
1453 	intern->ce = ce;
1454 	ZVAL_STR_COPY(reflection_prop_name(object), name);
1455 	ZVAL_STR_COPY(reflection_prop_class(object), prop ? prop->ce->name : ce->name);
1456 }
1457 /* }}} */
1458 
reflection_property_factory_str(zend_class_entry * ce,const char * name_str,size_t name_len,zend_property_info * prop,zval * object)1459 static void reflection_property_factory_str(zend_class_entry *ce, const char *name_str, size_t name_len, zend_property_info *prop, zval *object)
1460 {
1461 	zend_string *name = zend_string_init(name_str, name_len, 0);
1462 	reflection_property_factory(ce, name, prop, object);
1463 	zend_string_release(name);
1464 }
1465 
1466 /* {{{ reflection_class_constant_factory */
reflection_class_constant_factory(zend_string * name_str,zend_class_constant * constant,zval * object)1467 static void reflection_class_constant_factory(zend_string *name_str, zend_class_constant *constant, zval *object)
1468 {
1469 	reflection_object *intern;
1470 
1471 	reflection_instantiate(reflection_class_constant_ptr, object);
1472 	intern = Z_REFLECTION_P(object);
1473 	intern->ptr = constant;
1474 	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
1475 	intern->ce = constant->ce;
1476 
1477 	ZVAL_STR_COPY(reflection_prop_name(object), name_str);
1478 	ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
1479 }
1480 /* }}} */
1481 
reflection_enum_case_factory(zend_class_entry * ce,zend_string * name_str,zend_class_constant * constant,zval * object)1482 static void reflection_enum_case_factory(zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object)
1483 {
1484 	reflection_object *intern;
1485 
1486 	zend_class_entry *case_reflection_class = ce->enum_backing_type == IS_UNDEF
1487 		? reflection_enum_unit_case_ptr
1488 		: reflection_enum_backed_case_ptr;
1489 	reflection_instantiate(case_reflection_class, object);
1490 	intern = Z_REFLECTION_P(object);
1491 	intern->ptr = constant;
1492 	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
1493 	intern->ce = constant->ce;
1494 
1495 	ZVAL_STR_COPY(reflection_prop_name(object), name_str);
1496 	ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
1497 }
1498 
get_parameter_default(zval * result,parameter_reference * param)1499 static int get_parameter_default(zval *result, parameter_reference *param) {
1500 	if (param->fptr->type == ZEND_INTERNAL_FUNCTION) {
1501 		if (param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO) {
1502 			/* We don't have a way to determine the default value for this case right now. */
1503 			return FAILURE;
1504 		}
1505 		return zend_get_default_from_internal_arg_info(
1506 			result, (zend_internal_arg_info *) param->arg_info);
1507 	} else {
1508 		zval *default_value = get_default_from_recv((zend_op_array *) param->fptr, param->offset);
1509 		if (!default_value) {
1510 			return FAILURE;
1511 		}
1512 
1513 		ZVAL_COPY(result, default_value);
1514 		return SUCCESS;
1515 	}
1516 }
1517 
1518 /* {{{ Preventing __clone from being called */
ZEND_METHOD(ReflectionClass,__clone)1519 ZEND_METHOD(ReflectionClass, __clone)
1520 {
1521 	/* Should never be executable */
1522 	_DO_THROW("Cannot clone object using __clone()");
1523 }
1524 /* }}} */
1525 
1526 /* {{{ Returns an array of modifier names */
ZEND_METHOD(Reflection,getModifierNames)1527 ZEND_METHOD(Reflection, getModifierNames)
1528 {
1529 	zend_long modifiers;
1530 
1531 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &modifiers) == FAILURE) {
1532 		RETURN_THROWS();
1533 	}
1534 
1535 	array_init(return_value);
1536 
1537 	if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1538 		add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1);
1539 	}
1540 	if (modifiers & ZEND_ACC_FINAL) {
1541 		add_next_index_stringl(return_value, "final", sizeof("final")-1);
1542 	}
1543 
1544 	/* These are mutually exclusive */
1545 	switch (modifiers & ZEND_ACC_PPP_MASK) {
1546 		case ZEND_ACC_PUBLIC:
1547 			add_next_index_stringl(return_value, "public", sizeof("public")-1);
1548 			break;
1549 		case ZEND_ACC_PRIVATE:
1550 			add_next_index_stringl(return_value, "private", sizeof("private")-1);
1551 			break;
1552 		case ZEND_ACC_PROTECTED:
1553 			add_next_index_stringl(return_value, "protected", sizeof("protected")-1);
1554 			break;
1555 	}
1556 
1557 	if (modifiers & ZEND_ACC_STATIC) {
1558 		add_next_index_stringl(return_value, "static", sizeof("static")-1);
1559 	}
1560 
1561 	if (modifiers & (ZEND_ACC_READONLY | ZEND_ACC_READONLY_CLASS)) {
1562 		add_next_index_stringl(return_value, "readonly", sizeof("readonly")-1);
1563 	}
1564 }
1565 /* }}} */
1566 
1567 /* {{{ Constructor. Throws an Exception in case the given function does not exist */
ZEND_METHOD(ReflectionFunction,__construct)1568 ZEND_METHOD(ReflectionFunction, __construct)
1569 {
1570 	zval *object;
1571 	zend_object *closure_obj = NULL;
1572 	reflection_object *intern;
1573 	zend_function *fptr;
1574 	zend_string *fname, *lcname;
1575 
1576 	object = ZEND_THIS;
1577 	intern = Z_REFLECTION_P(object);
1578 
1579 	ZEND_PARSE_PARAMETERS_START(1, 1)
1580 		Z_PARAM_OBJ_OF_CLASS_OR_STR(closure_obj, zend_ce_closure, fname)
1581 	ZEND_PARSE_PARAMETERS_END();
1582 
1583 	if (closure_obj) {
1584 		fptr = (zend_function*)zend_get_closure_method_def(closure_obj);
1585 	} else {
1586 		if (UNEXPECTED(ZSTR_VAL(fname)[0] == '\\')) {
1587 			/* Ignore leading "\" */
1588 			ALLOCA_FLAG(use_heap)
1589 			ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(fname) - 1, use_heap);
1590 			zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(fname) + 1, ZSTR_LEN(fname) - 1);
1591 			fptr = zend_fetch_function(lcname);
1592 			ZSTR_ALLOCA_FREE(lcname, use_heap);
1593 		} else {
1594 			lcname = zend_string_tolower(fname);
1595 			fptr = zend_fetch_function(lcname);
1596 			zend_string_release(lcname);
1597 		}
1598 
1599 		if (fptr == NULL) {
1600 			zend_throw_exception_ex(reflection_exception_ptr, 0,
1601 				"Function %s() does not exist", ZSTR_VAL(fname));
1602 			RETURN_THROWS();
1603 		}
1604 	}
1605 
1606 	if (intern->ptr) {
1607 		zval_ptr_dtor(&intern->obj);
1608 		zval_ptr_dtor(reflection_prop_name(object));
1609 	}
1610 
1611 	ZVAL_STR_COPY(reflection_prop_name(object), fptr->common.function_name);
1612 	intern->ptr = fptr;
1613 	intern->ref_type = REF_TYPE_FUNCTION;
1614 	if (closure_obj) {
1615 		ZVAL_OBJ_COPY(&intern->obj, closure_obj);
1616 	} else {
1617 		ZVAL_UNDEF(&intern->obj);
1618 	}
1619 	intern->ce = NULL;
1620 }
1621 /* }}} */
1622 
1623 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionFunction,__toString)1624 ZEND_METHOD(ReflectionFunction, __toString)
1625 {
1626 	reflection_object *intern;
1627 	zend_function *fptr;
1628 	smart_str str = {0};
1629 
1630 	if (zend_parse_parameters_none() == FAILURE) {
1631 		RETURN_THROWS();
1632 	}
1633 	GET_REFLECTION_OBJECT_PTR(fptr);
1634 	_function_string(&str, fptr, intern->ce, "");
1635 	RETURN_STR(smart_str_extract(&str));
1636 }
1637 /* }}} */
1638 
1639 /* {{{ Returns this function's name */
ZEND_METHOD(ReflectionFunctionAbstract,getName)1640 ZEND_METHOD(ReflectionFunctionAbstract, getName)
1641 {
1642 	reflection_object *intern;
1643 	zend_function *fptr;
1644 
1645 	if (zend_parse_parameters_none() == FAILURE) {
1646 		RETURN_THROWS();
1647 	}
1648 
1649 	GET_REFLECTION_OBJECT_PTR(fptr);
1650 	RETURN_STR_COPY(fptr->common.function_name);
1651 }
1652 /* }}} */
1653 
1654 /* {{{ Returns whether this is a closure */
ZEND_METHOD(ReflectionFunctionAbstract,isClosure)1655 ZEND_METHOD(ReflectionFunctionAbstract, isClosure)
1656 {
1657 	reflection_object *intern;
1658 	zend_function *fptr;
1659 
1660 	if (zend_parse_parameters_none() == FAILURE) {
1661 		RETURN_THROWS();
1662 	}
1663 	GET_REFLECTION_OBJECT_PTR(fptr);
1664 	RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_CLOSURE);
1665 }
1666 /* }}} */
1667 
1668 /* {{{ Returns this pointer bound to closure */
ZEND_METHOD(ReflectionFunctionAbstract,getClosureThis)1669 ZEND_METHOD(ReflectionFunctionAbstract, getClosureThis)
1670 {
1671 	reflection_object *intern;
1672 	zval* closure_this;
1673 
1674 	if (zend_parse_parameters_none() == FAILURE) {
1675 		RETURN_THROWS();
1676 	}
1677 	GET_REFLECTION_OBJECT();
1678 	if (!Z_ISUNDEF(intern->obj)) {
1679 		closure_this = zend_get_closure_this_ptr(&intern->obj);
1680 		if (!Z_ISUNDEF_P(closure_this)) {
1681 			RETURN_OBJ_COPY(Z_OBJ_P(closure_this));
1682 		}
1683 	}
1684 }
1685 /* }}} */
1686 
1687 /* {{{ Returns the scope associated to the closure */
ZEND_METHOD(ReflectionFunctionAbstract,getClosureScopeClass)1688 ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass)
1689 {
1690 	reflection_object *intern;
1691 	const zend_function *closure_func;
1692 
1693 	if (zend_parse_parameters_none() == FAILURE) {
1694 		RETURN_THROWS();
1695 	}
1696 	GET_REFLECTION_OBJECT();
1697 	if (!Z_ISUNDEF(intern->obj)) {
1698 		closure_func = zend_get_closure_method_def(Z_OBJ(intern->obj));
1699 		if (closure_func && closure_func->common.scope) {
1700 			zend_reflection_class_factory(closure_func->common.scope, return_value);
1701 		}
1702 	}
1703 }
1704 /* }}} */
1705 
1706 /* {{{ Returns the called scope associated to the closure */
ZEND_METHOD(ReflectionFunctionAbstract,getClosureCalledClass)1707 ZEND_METHOD(ReflectionFunctionAbstract, getClosureCalledClass)
1708 {
1709 	reflection_object *intern;
1710 
1711 	if (zend_parse_parameters_none() == FAILURE) {
1712 		RETURN_THROWS();
1713 	}
1714 	GET_REFLECTION_OBJECT();
1715 	if (!Z_ISUNDEF(intern->obj)) {
1716 		zend_class_entry *called_scope;
1717 		zend_function *closure_func;
1718 		zend_object *object;
1719 		if (Z_OBJ_HANDLER(intern->obj, get_closure)
1720 		 && Z_OBJ_HANDLER(intern->obj, get_closure)(Z_OBJ(intern->obj), &called_scope, &closure_func, &object, 1) == SUCCESS
1721 		 && closure_func && (called_scope || closure_func->common.scope)) {
1722 			zend_reflection_class_factory(called_scope ? (zend_class_entry *) called_scope : closure_func->common.scope, return_value);
1723 		}
1724 	}
1725 }
1726 /* }}} */
1727 
1728 /* {{{ Returns an associative array containing the closures lexical scope variables */
ZEND_METHOD(ReflectionFunctionAbstract,getClosureUsedVariables)1729 ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables)
1730 {
1731 	reflection_object *intern;
1732 	const zend_function *closure_func;
1733 
1734 	if (zend_parse_parameters_none() == FAILURE) {
1735 		RETURN_THROWS();
1736 	}
1737 	GET_REFLECTION_OBJECT();
1738 
1739 	array_init(return_value);
1740 	if (!Z_ISUNDEF(intern->obj)) {
1741 		closure_func = zend_get_closure_method_def(Z_OBJ(intern->obj));
1742 		if (closure_func == NULL ||
1743 			closure_func->type != ZEND_USER_FUNCTION ||
1744 			closure_func->op_array.static_variables == NULL) {
1745 			return;
1746 		}
1747 
1748 		const zend_op_array *ops = &closure_func->op_array;
1749 
1750 		HashTable *static_variables = ZEND_MAP_PTR_GET(ops->static_variables_ptr);
1751 
1752 		if (!static_variables) {
1753 			return;
1754 		}
1755 
1756 		zend_op *opline = ops->opcodes + ops->num_args;
1757 		if (ops->fn_flags & ZEND_ACC_VARIADIC) {
1758 			opline++;
1759 		}
1760 
1761 		for (; opline->opcode == ZEND_BIND_STATIC; opline++)  {
1762 			if (!(opline->extended_value & (ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))) {
1763 				continue;
1764 			}
1765 
1766 			Bucket *bucket = (Bucket*)
1767 				(((char*)static_variables->arData) +
1768 				(opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
1769 
1770 			if (Z_ISUNDEF(bucket->val)) {
1771 				continue;
1772 			}
1773 
1774 			zend_hash_add_new(Z_ARRVAL_P(return_value), bucket->key, &bucket->val);
1775 			Z_TRY_ADDREF(bucket->val);
1776 		}
1777 	}
1778 } /* }}} */
1779 
1780 /* {{{ Returns a dynamically created closure for the function */
ZEND_METHOD(ReflectionFunction,getClosure)1781 ZEND_METHOD(ReflectionFunction, getClosure)
1782 {
1783 	reflection_object *intern;
1784 	zend_function *fptr;
1785 
1786 	if (zend_parse_parameters_none() == FAILURE) {
1787 		RETURN_THROWS();
1788 	}
1789 	GET_REFLECTION_OBJECT_PTR(fptr);
1790 
1791 	if (!Z_ISUNDEF(intern->obj)) {
1792 		/* Closures are immutable objects */
1793 		RETURN_OBJ_COPY(Z_OBJ(intern->obj));
1794 	} else {
1795 		zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL);
1796 	}
1797 }
1798 /* }}} */
1799 
1800 /* {{{ Returns whether this is an internal function */
ZEND_METHOD(ReflectionFunctionAbstract,isInternal)1801 ZEND_METHOD(ReflectionFunctionAbstract, isInternal)
1802 {
1803 	reflection_object *intern;
1804 	zend_function *fptr;
1805 
1806 	if (zend_parse_parameters_none() == FAILURE) {
1807 		RETURN_THROWS();
1808 	}
1809 	GET_REFLECTION_OBJECT_PTR(fptr);
1810 	RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION);
1811 }
1812 /* }}} */
1813 
1814 /* {{{ Returns whether this is a user-defined function */
ZEND_METHOD(ReflectionFunctionAbstract,isUserDefined)1815 ZEND_METHOD(ReflectionFunctionAbstract, isUserDefined)
1816 {
1817 	reflection_object *intern;
1818 	zend_function *fptr;
1819 
1820 	if (zend_parse_parameters_none() == FAILURE) {
1821 		RETURN_THROWS();
1822 	}
1823 	GET_REFLECTION_OBJECT_PTR(fptr);
1824 	RETURN_BOOL(fptr->type == ZEND_USER_FUNCTION);
1825 }
1826 /* }}} */
1827 
1828 /* {{{ Returns whether this function is an anonymous closure or not */
ZEND_METHOD(ReflectionFunction,isAnonymous)1829 ZEND_METHOD(ReflectionFunction, isAnonymous)
1830 {
1831 	reflection_object *intern;
1832 	zend_function *fptr;
1833 
1834 	ZEND_PARSE_PARAMETERS_NONE();
1835 
1836 	GET_REFLECTION_OBJECT_PTR(fptr);
1837 	RETURN_BOOL((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE);
1838 }
1839 /* }}} */
1840 
1841 /* {{{ Returns whether this function has been disabled or not */
ZEND_METHOD(ReflectionFunction,isDisabled)1842 ZEND_METHOD(ReflectionFunction, isDisabled)
1843 {
1844 	if (zend_parse_parameters_none() == FAILURE) {
1845 		RETURN_THROWS();
1846 	}
1847 
1848 	/* A disabled function cannot be queried using Reflection. */
1849 	RETURN_FALSE;
1850 }
1851 /* }}} */
1852 
1853 /* {{{ Returns the filename of the file this function was declared in */
ZEND_METHOD(ReflectionFunctionAbstract,getFileName)1854 ZEND_METHOD(ReflectionFunctionAbstract, getFileName)
1855 {
1856 	reflection_object *intern;
1857 	zend_function *fptr;
1858 
1859 	if (zend_parse_parameters_none() == FAILURE) {
1860 		RETURN_THROWS();
1861 	}
1862 	GET_REFLECTION_OBJECT_PTR(fptr);
1863 	if (fptr->type == ZEND_USER_FUNCTION) {
1864 		RETURN_STR_COPY(fptr->op_array.filename);
1865 	}
1866 	RETURN_FALSE;
1867 }
1868 /* }}} */
1869 
1870 /* {{{ Returns the line this function's declaration starts at */
ZEND_METHOD(ReflectionFunctionAbstract,getStartLine)1871 ZEND_METHOD(ReflectionFunctionAbstract, getStartLine)
1872 {
1873 	reflection_object *intern;
1874 	zend_function *fptr;
1875 
1876 	if (zend_parse_parameters_none() == FAILURE) {
1877 		RETURN_THROWS();
1878 	}
1879 	GET_REFLECTION_OBJECT_PTR(fptr);
1880 	if (fptr->type == ZEND_USER_FUNCTION) {
1881 		RETURN_LONG(fptr->op_array.line_start);
1882 	}
1883 	RETURN_FALSE;
1884 }
1885 /* }}} */
1886 
1887 /* {{{ Returns the line this function's declaration ends at */
ZEND_METHOD(ReflectionFunctionAbstract,getEndLine)1888 ZEND_METHOD(ReflectionFunctionAbstract, getEndLine)
1889 {
1890 	reflection_object *intern;
1891 	zend_function *fptr;
1892 
1893 	if (zend_parse_parameters_none() == FAILURE) {
1894 		RETURN_THROWS();
1895 	}
1896 	GET_REFLECTION_OBJECT_PTR(fptr);
1897 	if (fptr->type == ZEND_USER_FUNCTION) {
1898 		RETURN_LONG(fptr->op_array.line_end);
1899 	}
1900 	RETURN_FALSE;
1901 }
1902 /* }}} */
1903 
1904 /* {{{ Returns the doc comment for this function */
ZEND_METHOD(ReflectionFunctionAbstract,getDocComment)1905 ZEND_METHOD(ReflectionFunctionAbstract, getDocComment)
1906 {
1907 	reflection_object *intern;
1908 	zend_function *fptr;
1909 
1910 	if (zend_parse_parameters_none() == FAILURE) {
1911 		RETURN_THROWS();
1912 	}
1913 	GET_REFLECTION_OBJECT_PTR(fptr);
1914 	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
1915 		RETURN_STR_COPY(fptr->op_array.doc_comment);
1916 	}
1917 	RETURN_FALSE;
1918 }
1919 /* }}} */
1920 
1921 /* {{{ Returns the attributes of this function */
ZEND_METHOD(ReflectionFunctionAbstract,getAttributes)1922 ZEND_METHOD(ReflectionFunctionAbstract, getAttributes)
1923 {
1924 	reflection_object *intern;
1925 	zend_function *fptr;
1926 	uint32_t target;
1927 
1928 	GET_REFLECTION_OBJECT_PTR(fptr);
1929 
1930 	if (fptr->common.scope && (fptr->common.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) {
1931 		target = ZEND_ATTRIBUTE_TARGET_METHOD;
1932 	} else {
1933 		target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
1934 	}
1935 
1936 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
1937 		fptr->common.attributes, 0, fptr->common.scope, target,
1938 		fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL);
1939 }
1940 /* }}} */
1941 
1942 /* {{{ Returns an associative array containing this function's static variables and their values */
ZEND_METHOD(ReflectionFunctionAbstract,getStaticVariables)1943 ZEND_METHOD(ReflectionFunctionAbstract, getStaticVariables)
1944 {
1945 	reflection_object *intern;
1946 	zend_function *fptr;
1947 	zval *val;
1948 
1949 	if (zend_parse_parameters_none() == FAILURE) {
1950 		RETURN_THROWS();
1951 	}
1952 	GET_REFLECTION_OBJECT_PTR(fptr);
1953 
1954 	/* Return an empty array in case no static variables exist */
1955 	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
1956 		HashTable *ht;
1957 
1958 		array_init(return_value);
1959 		ht = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
1960 		if (!ht) {
1961 			ht = zend_array_dup(fptr->op_array.static_variables);
1962 			ZEND_MAP_PTR_SET(fptr->op_array.static_variables_ptr, ht);
1963 		}
1964 		ZEND_HASH_MAP_FOREACH_VAL(ht, val) {
1965 			if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) {
1966 				RETURN_THROWS();
1967 			}
1968 		} ZEND_HASH_FOREACH_END();
1969 		zend_hash_copy(Z_ARRVAL_P(return_value), ht, zval_add_ref);
1970 	} else {
1971 		RETURN_EMPTY_ARRAY();
1972 	}
1973 }
1974 /* }}} */
1975 
1976 /* {{{ Invokes the function */
ZEND_METHOD(ReflectionFunction,invoke)1977 ZEND_METHOD(ReflectionFunction, invoke)
1978 {
1979 	zval retval;
1980 	zval *params;
1981 	int result, num_args;
1982 	HashTable *named_params;
1983 	zend_fcall_info fci;
1984 	zend_fcall_info_cache fcc;
1985 	reflection_object *intern;
1986 	zend_function *fptr;
1987 
1988 	ZEND_PARSE_PARAMETERS_START(0, -1)
1989 		Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params)
1990 	ZEND_PARSE_PARAMETERS_END();
1991 
1992 	GET_REFLECTION_OBJECT_PTR(fptr);
1993 
1994 	fci.size = sizeof(fci);
1995 	ZVAL_UNDEF(&fci.function_name);
1996 	fci.object = NULL;
1997 	fci.retval = &retval;
1998 	fci.param_count = num_args;
1999 	fci.params = params;
2000 	fci.named_params = named_params;
2001 
2002 	fcc.function_handler = fptr;
2003 	fcc.called_scope = NULL;
2004 	fcc.object = NULL;
2005 
2006 	if (!Z_ISUNDEF(intern->obj)) {
2007 		Z_OBJ_HT(intern->obj)->get_closure(
2008 			Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, 0);
2009 	}
2010 
2011 	result = zend_call_function(&fci, &fcc);
2012 
2013 	if (result == FAILURE) {
2014 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2015 			"Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name));
2016 		RETURN_THROWS();
2017 	}
2018 
2019 	if (Z_TYPE(retval) != IS_UNDEF) {
2020 		if (Z_ISREF(retval)) {
2021 			zend_unwrap_reference(&retval);
2022 		}
2023 		ZVAL_COPY_VALUE(return_value, &retval);
2024 	}
2025 }
2026 /* }}} */
2027 
2028 /* {{{ Invokes the function and pass its arguments as array. */
ZEND_METHOD(ReflectionFunction,invokeArgs)2029 ZEND_METHOD(ReflectionFunction, invokeArgs)
2030 {
2031 	zval retval;
2032 	int result;
2033 	zend_fcall_info fci;
2034 	zend_fcall_info_cache fcc;
2035 	reflection_object *intern;
2036 	zend_function *fptr;
2037 	HashTable *params;
2038 
2039 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &params) == FAILURE) {
2040 		RETURN_THROWS();
2041 	}
2042 
2043 	GET_REFLECTION_OBJECT_PTR(fptr);
2044 
2045 	fci.size = sizeof(fci);
2046 	ZVAL_UNDEF(&fci.function_name);
2047 	fci.object = NULL;
2048 	fci.retval = &retval;
2049 	fci.param_count = 0;
2050 	fci.params = NULL;
2051 	fci.named_params = params;
2052 
2053 	fcc.function_handler = fptr;
2054 	fcc.called_scope = NULL;
2055 	fcc.object = NULL;
2056 
2057 	if (!Z_ISUNDEF(intern->obj)) {
2058 		Z_OBJ_HT(intern->obj)->get_closure(
2059 			Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, 0);
2060 	}
2061 
2062 	result = zend_call_function(&fci, &fcc);
2063 
2064 	if (result == FAILURE) {
2065 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2066 			"Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name));
2067 		RETURN_THROWS();
2068 	}
2069 
2070 	if (Z_TYPE(retval) != IS_UNDEF) {
2071 		if (Z_ISREF(retval)) {
2072 			zend_unwrap_reference(&retval);
2073 		}
2074 		ZVAL_COPY_VALUE(return_value, &retval);
2075 	}
2076 }
2077 /* }}} */
2078 
2079 /* {{{ Gets whether this function returns a reference */
ZEND_METHOD(ReflectionFunctionAbstract,returnsReference)2080 ZEND_METHOD(ReflectionFunctionAbstract, returnsReference)
2081 {
2082 	reflection_object *intern;
2083 	zend_function *fptr;
2084 
2085 	if (zend_parse_parameters_none() == FAILURE) {
2086 		RETURN_THROWS();
2087 	}
2088 
2089 	GET_REFLECTION_OBJECT_PTR(fptr);
2090 
2091 	RETURN_BOOL((fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0);
2092 }
2093 /* }}} */
2094 
2095 /* {{{ Gets the number of parameters */
ZEND_METHOD(ReflectionFunctionAbstract,getNumberOfParameters)2096 ZEND_METHOD(ReflectionFunctionAbstract, getNumberOfParameters)
2097 {
2098 	reflection_object *intern;
2099 	zend_function *fptr;
2100 	uint32_t num_args;
2101 
2102 	if (zend_parse_parameters_none() == FAILURE) {
2103 		RETURN_THROWS();
2104 	}
2105 
2106 	GET_REFLECTION_OBJECT_PTR(fptr);
2107 
2108 	num_args = fptr->common.num_args;
2109 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2110 		num_args++;
2111 	}
2112 
2113 	RETURN_LONG(num_args);
2114 }
2115 /* }}} */
2116 
2117 /* {{{ Gets the number of required parameters */
ZEND_METHOD(ReflectionFunctionAbstract,getNumberOfRequiredParameters)2118 ZEND_METHOD(ReflectionFunctionAbstract, getNumberOfRequiredParameters)
2119 {
2120 	reflection_object *intern;
2121 	zend_function *fptr;
2122 
2123 	if (zend_parse_parameters_none() == FAILURE) {
2124 		RETURN_THROWS();
2125 	}
2126 
2127 	GET_REFLECTION_OBJECT_PTR(fptr);
2128 
2129 	RETURN_LONG(fptr->common.required_num_args);
2130 }
2131 /* }}} */
2132 
2133 /* {{{ Returns an array of parameter objects for this function */
ZEND_METHOD(ReflectionFunctionAbstract,getParameters)2134 ZEND_METHOD(ReflectionFunctionAbstract, getParameters)
2135 {
2136 	reflection_object *intern;
2137 	zend_function *fptr;
2138 	uint32_t i, num_args;
2139 	struct _zend_arg_info *arg_info;
2140 
2141 	if (zend_parse_parameters_none() == FAILURE) {
2142 		RETURN_THROWS();
2143 	}
2144 
2145 	GET_REFLECTION_OBJECT_PTR(fptr);
2146 
2147 	arg_info= fptr->common.arg_info;
2148 	num_args = fptr->common.num_args;
2149 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2150 		num_args++;
2151 	}
2152 
2153 	if (!num_args) {
2154 		RETURN_EMPTY_ARRAY();
2155 	}
2156 
2157 	array_init(return_value);
2158 	for (i = 0; i < num_args; i++) {
2159 		zval parameter;
2160 
2161 		reflection_parameter_factory(
2162 			_copy_function(fptr),
2163 			Z_ISUNDEF(intern->obj) ? NULL : &intern->obj,
2164 			arg_info,
2165 			i,
2166 			i < fptr->common.required_num_args,
2167 			&parameter
2168 		);
2169 		zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &parameter);
2170 
2171 		arg_info++;
2172 	}
2173 }
2174 /* }}} */
2175 
2176 /* {{{ Returns NULL or the extension the function belongs to */
ZEND_METHOD(ReflectionFunctionAbstract,getExtension)2177 ZEND_METHOD(ReflectionFunctionAbstract, getExtension)
2178 {
2179 	reflection_object *intern;
2180 	zend_function *fptr;
2181 	zend_internal_function *internal;
2182 
2183 	if (zend_parse_parameters_none() == FAILURE) {
2184 		RETURN_THROWS();
2185 	}
2186 
2187 	GET_REFLECTION_OBJECT_PTR(fptr);
2188 
2189 	if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2190 		RETURN_NULL();
2191 	}
2192 
2193 	internal = (zend_internal_function *)fptr;
2194 	if (internal->module) {
2195 		reflection_extension_factory(return_value, internal->module->name);
2196 	} else {
2197 		RETURN_NULL();
2198 	}
2199 }
2200 /* }}} */
2201 
2202 /* {{{ Returns false or the name of the extension the function belongs to */
ZEND_METHOD(ReflectionFunctionAbstract,getExtensionName)2203 ZEND_METHOD(ReflectionFunctionAbstract, getExtensionName)
2204 {
2205 	reflection_object *intern;
2206 	zend_function *fptr;
2207 	zend_internal_function *internal;
2208 
2209 	if (zend_parse_parameters_none() == FAILURE) {
2210 		RETURN_THROWS();
2211 	}
2212 
2213 	GET_REFLECTION_OBJECT_PTR(fptr);
2214 
2215 	if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2216 		RETURN_FALSE;
2217 	}
2218 
2219 	internal = (zend_internal_function *)fptr;
2220 	if (internal->module) {
2221 		RETURN_STRING(internal->module->name);
2222 	} else {
2223 		RETURN_FALSE;
2224 	}
2225 }
2226 /* }}} */
2227 
2228 /* {{{ */
ZEND_METHOD(ReflectionGenerator,__construct)2229 ZEND_METHOD(ReflectionGenerator, __construct)
2230 {
2231 	zval *generator, *object;
2232 	reflection_object *intern;
2233 	zend_execute_data *ex;
2234 
2235 	object = ZEND_THIS;
2236 	intern = Z_REFLECTION_P(object);
2237 
2238 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) {
2239 		RETURN_THROWS();
2240 	}
2241 
2242 	ex = ((zend_generator *) Z_OBJ_P(generator))->execute_data;
2243 	if (!ex) {
2244 		_DO_THROW("Cannot create ReflectionGenerator based on a terminated Generator");
2245 		RETURN_THROWS();
2246 	}
2247 
2248 	if (intern->ce) {
2249 		zval_ptr_dtor(&intern->obj);
2250 	}
2251 
2252 	intern->ref_type = REF_TYPE_GENERATOR;
2253 	ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(generator));
2254 	intern->ce = zend_ce_generator;
2255 }
2256 /* }}} */
2257 
2258 #define REFLECTION_CHECK_VALID_GENERATOR(ex) \
2259 	if (!ex) { \
2260 		_DO_THROW("Cannot fetch information from a terminated Generator"); \
2261 		RETURN_THROWS(); \
2262 	}
2263 
2264 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getTrace)2265 ZEND_METHOD(ReflectionGenerator, getTrace)
2266 {
2267 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
2268 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2269 	zend_generator *root_generator;
2270 	zend_execute_data *ex_backup = EG(current_execute_data);
2271 	zend_execute_data *ex = generator->execute_data;
2272 	zend_execute_data *root_prev = NULL, *cur_prev;
2273 
2274 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &options) == FAILURE) {
2275 		RETURN_THROWS();
2276 	}
2277 
2278 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2279 
2280 	root_generator = zend_generator_get_current(generator);
2281 
2282 	cur_prev = generator->execute_data->prev_execute_data;
2283 	if (generator == root_generator) {
2284 		generator->execute_data->prev_execute_data = NULL;
2285 	} else {
2286 		root_prev = root_generator->execute_data->prev_execute_data;
2287 		generator->execute_fake.prev_execute_data = NULL;
2288 		root_generator->execute_data->prev_execute_data = &generator->execute_fake;
2289 	}
2290 
2291 	EG(current_execute_data) = root_generator->execute_data;
2292 	zend_fetch_debug_backtrace(return_value, 0, options, 0);
2293 	EG(current_execute_data) = ex_backup;
2294 
2295 	root_generator->execute_data->prev_execute_data = root_prev;
2296 	generator->execute_data->prev_execute_data = cur_prev;
2297 }
2298 /* }}} */
2299 
2300 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getExecutingLine)2301 ZEND_METHOD(ReflectionGenerator, getExecutingLine)
2302 {
2303 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2304 	zend_execute_data *ex = generator->execute_data;
2305 
2306 	if (zend_parse_parameters_none() == FAILURE) {
2307 		RETURN_THROWS();
2308 	}
2309 
2310 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2311 
2312 	ZVAL_LONG(return_value, ex->opline->lineno);
2313 }
2314 /* }}} */
2315 
2316 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getExecutingFile)2317 ZEND_METHOD(ReflectionGenerator, getExecutingFile)
2318 {
2319 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2320 	zend_execute_data *ex = generator->execute_data;
2321 
2322 	if (zend_parse_parameters_none() == FAILURE) {
2323 		RETURN_THROWS();
2324 	}
2325 
2326 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2327 
2328 	ZVAL_STR_COPY(return_value, ex->func->op_array.filename);
2329 }
2330 /* }}} */
2331 
2332 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getFunction)2333 ZEND_METHOD(ReflectionGenerator, getFunction)
2334 {
2335 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2336 	zend_execute_data *ex = generator->execute_data;
2337 
2338 	if (zend_parse_parameters_none() == FAILURE) {
2339 		RETURN_THROWS();
2340 	}
2341 
2342 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2343 
2344 	if (ex->func->common.fn_flags & ZEND_ACC_CLOSURE) {
2345 		zval closure;
2346 		ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(ex->func));
2347 		reflection_function_factory(ex->func, &closure, return_value);
2348 	} else if (ex->func->op_array.scope) {
2349 		reflection_method_factory(ex->func->op_array.scope, ex->func, NULL, return_value);
2350 	} else {
2351 		reflection_function_factory(ex->func, NULL, return_value);
2352 	}
2353 }
2354 /* }}} */
2355 
2356 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getThis)2357 ZEND_METHOD(ReflectionGenerator, getThis)
2358 {
2359 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2360 	zend_execute_data *ex = generator->execute_data;
2361 
2362 	if (zend_parse_parameters_none() == FAILURE) {
2363 		RETURN_THROWS();
2364 	}
2365 
2366 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2367 
2368 	if (Z_TYPE(ex->This) == IS_OBJECT) {
2369 		RETURN_OBJ_COPY(Z_OBJ(ex->This));
2370 	} else {
2371 		RETURN_NULL();
2372 	}
2373 }
2374 /* }}} */
2375 
2376 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getExecutingGenerator)2377 ZEND_METHOD(ReflectionGenerator, getExecutingGenerator)
2378 {
2379 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2380 	zend_execute_data *ex = generator->execute_data;
2381 	zend_generator *current;
2382 
2383 	if (zend_parse_parameters_none() == FAILURE) {
2384 		RETURN_THROWS();
2385 	}
2386 
2387 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2388 
2389 	current = zend_generator_get_current(generator);
2390 	RETURN_OBJ_COPY(&current->std);
2391 }
2392 /* }}} */
2393 
2394 /* {{{ Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHOD(ReflectionParameter,__construct)2395 ZEND_METHOD(ReflectionParameter, __construct)
2396 {
2397 	parameter_reference *ref;
2398 	zval *reference;
2399 	zend_string *arg_name = NULL;
2400 	zend_long position;
2401 	zval *object;
2402 	zval *prop_name;
2403 	reflection_object *intern;
2404 	zend_function *fptr;
2405 	struct _zend_arg_info *arg_info;
2406 	uint32_t num_args;
2407 	zend_class_entry *ce = NULL;
2408 	bool is_closure = 0;
2409 
2410 	ZEND_PARSE_PARAMETERS_START(2, 2)
2411 		Z_PARAM_ZVAL(reference)
2412 		Z_PARAM_STR_OR_LONG(arg_name, position)
2413 	ZEND_PARSE_PARAMETERS_END();
2414 
2415 	object = ZEND_THIS;
2416 	intern = Z_REFLECTION_P(object);
2417 
2418 	/* First, find the function */
2419 	switch (Z_TYPE_P(reference)) {
2420 		case IS_STRING:
2421 			{
2422 				zend_string *lcname = zend_string_tolower(Z_STR_P(reference));
2423 				fptr = zend_hash_find_ptr(EG(function_table), lcname);
2424 				zend_string_release(lcname);
2425 				if (!fptr) {
2426 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2427 						"Function %s() does not exist", Z_STRVAL_P(reference));
2428 					RETURN_THROWS();
2429 				}
2430 				ce = fptr->common.scope;
2431 			}
2432 			break;
2433 
2434 		case IS_ARRAY: {
2435 				zval *classref;
2436 				zval *method;
2437 				zend_string *name, *lcname;
2438 
2439 				if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
2440 					|| ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL))
2441 				{
2442 					_DO_THROW("Expected array($object, $method) or array($classname, $method)");
2443 					RETURN_THROWS();
2444 				}
2445 
2446 				if (Z_TYPE_P(classref) == IS_OBJECT) {
2447 					ce = Z_OBJCE_P(classref);
2448 				} else {
2449 					name = zval_try_get_string(classref);
2450 					if (UNEXPECTED(!name)) {
2451 						return;
2452 					}
2453 					if ((ce = zend_lookup_class(name)) == NULL) {
2454 						zend_throw_exception_ex(reflection_exception_ptr, 0,
2455 								"Class \"%s\" does not exist", ZSTR_VAL(name));
2456 						zend_string_release(name);
2457 						RETURN_THROWS();
2458 					}
2459 					zend_string_release(name);
2460 				}
2461 
2462 				name = zval_try_get_string(method);
2463 				if (UNEXPECTED(!name)) {
2464 					return;
2465 				}
2466 
2467 				lcname = zend_string_tolower(name);
2468 				if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname)
2469 					&& (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
2470 				{
2471 					/* nothing to do. don't set is_closure since is the invoke handler,
2472 					   not the closure itself */
2473 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
2474 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2475 						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
2476 					zend_string_release(name);
2477 					zend_string_release(lcname);
2478 					RETURN_THROWS();
2479 				}
2480 				zend_string_release(name);
2481 				zend_string_release(lcname);
2482 			}
2483 			break;
2484 
2485 		case IS_OBJECT: {
2486 				ce = Z_OBJCE_P(reference);
2487 
2488 				if (instanceof_function(ce, zend_ce_closure)) {
2489 					fptr = (zend_function *)zend_get_closure_method_def(Z_OBJ_P(reference));
2490 					Z_ADDREF_P(reference);
2491 					is_closure = 1;
2492 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) {
2493 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2494 						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME);
2495 					RETURN_THROWS();
2496 				}
2497 			}
2498 			break;
2499 
2500 		default:
2501 			zend_argument_error(reflection_exception_ptr, 1, "must be a string, an array(class, method), or a callable object, %s given", zend_zval_type_name(reference));
2502 			RETURN_THROWS();
2503 	}
2504 
2505 	/* Now, search for the parameter */
2506 	arg_info = fptr->common.arg_info;
2507 	num_args = fptr->common.num_args;
2508 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2509 		num_args++;
2510 	}
2511 	if (arg_name != NULL) {
2512 		uint32_t i;
2513 		position = -1;
2514 
2515 		if (has_internal_arg_info(fptr)) {
2516 			for (i = 0; i < num_args; i++) {
2517 				if (arg_info[i].name) {
2518 					if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, ZSTR_VAL(arg_name)) == 0) {
2519 						position = i;
2520 						break;
2521 					}
2522 				}
2523 			}
2524 		} else {
2525 			for (i = 0; i < num_args; i++) {
2526 				if (arg_info[i].name) {
2527 					if (zend_string_equals(arg_name, arg_info[i].name)) {
2528 						position = i;
2529 						break;
2530 					}
2531 				}
2532 			}
2533 		}
2534 		if (position == -1) {
2535 			_DO_THROW("The parameter specified by its name could not be found");
2536 			goto failure;
2537 		}
2538 	} else {
2539 		if (position < 0) {
2540 			zend_argument_value_error(2, "must be greater than or equal to 0");
2541 			goto failure;
2542 		}
2543 		if (position >= num_args) {
2544 			_DO_THROW("The parameter specified by its offset could not be found");
2545 			goto failure;
2546 		}
2547 	}
2548 
2549 	ref = (parameter_reference*) emalloc(sizeof(parameter_reference));
2550 	ref->arg_info = &arg_info[position];
2551 	ref->offset = (uint32_t)position;
2552 	ref->required = (uint32_t)position < fptr->common.required_num_args;
2553 	ref->fptr = fptr;
2554 	/* TODO: copy fptr */
2555 	intern->ptr = ref;
2556 	intern->ref_type = REF_TYPE_PARAMETER;
2557 	intern->ce = ce;
2558 	if (reference && is_closure) {
2559 		ZVAL_COPY_VALUE(&intern->obj, reference);
2560 	}
2561 
2562 	prop_name = reflection_prop_name(object);
2563 	if (has_internal_arg_info(fptr)) {
2564 		ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)[position].name);
2565 	} else {
2566 		ZVAL_STR_COPY(prop_name, arg_info[position].name);
2567 	}
2568 	return;
2569 
2570 failure:
2571 	if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2572 		zend_string_release_ex(fptr->common.function_name, 0);
2573 		zend_free_trampoline(fptr);
2574 	}
2575 	if (is_closure) {
2576 		zval_ptr_dtor(reference);
2577 	}
2578 	RETURN_THROWS();
2579 }
2580 /* }}} */
2581 
2582 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionParameter,__toString)2583 ZEND_METHOD(ReflectionParameter, __toString)
2584 {
2585 	reflection_object *intern;
2586 	parameter_reference *param;
2587 	smart_str str = {0};
2588 
2589 	if (zend_parse_parameters_none() == FAILURE) {
2590 		RETURN_THROWS();
2591 	}
2592 	GET_REFLECTION_OBJECT_PTR(param);
2593 	_parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "");
2594 	RETURN_STR(smart_str_extract(&str));
2595 }
2596 
2597 /* }}} */
2598 
2599 /* {{{ Returns this parameters's name */
ZEND_METHOD(ReflectionParameter,getName)2600 ZEND_METHOD(ReflectionParameter, getName)
2601 {
2602 	reflection_object *intern;
2603 	parameter_reference *param;
2604 
2605 	if (zend_parse_parameters_none() == FAILURE) {
2606 		RETURN_THROWS();
2607 	}
2608 
2609 	GET_REFLECTION_OBJECT_PTR(param);
2610 	if (has_internal_arg_info(param->fptr)) {
2611 		RETURN_STRING(((zend_internal_arg_info *) param->arg_info)->name);
2612 	} else {
2613 		RETURN_STR_COPY(param->arg_info->name);
2614 	}
2615 }
2616 /* }}} */
2617 
2618 /* {{{ Returns the ReflectionFunction for the function of this parameter */
ZEND_METHOD(ReflectionParameter,getDeclaringFunction)2619 ZEND_METHOD(ReflectionParameter, getDeclaringFunction)
2620 {
2621 	reflection_object *intern;
2622 	parameter_reference *param;
2623 
2624 	if (zend_parse_parameters_none() == FAILURE) {
2625 		RETURN_THROWS();
2626 	}
2627 	GET_REFLECTION_OBJECT_PTR(param);
2628 
2629 	if (!param->fptr->common.scope) {
2630 		reflection_function_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2631 	} else {
2632 		reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2633 	}
2634 }
2635 /* }}} */
2636 
2637 /* {{{ Returns in which class this parameter is defined (not the type of the parameter) */
ZEND_METHOD(ReflectionParameter,getDeclaringClass)2638 ZEND_METHOD(ReflectionParameter, getDeclaringClass)
2639 {
2640 	reflection_object *intern;
2641 	parameter_reference *param;
2642 
2643 	if (zend_parse_parameters_none() == FAILURE) {
2644 		RETURN_THROWS();
2645 	}
2646 	GET_REFLECTION_OBJECT_PTR(param);
2647 
2648 	if (param->fptr->common.scope) {
2649 		zend_reflection_class_factory(param->fptr->common.scope, return_value);
2650 	}
2651 }
2652 /* }}} */
2653 
2654 /* {{{ Returns this parameters's class hint or NULL if there is none */
ZEND_METHOD(ReflectionParameter,getClass)2655 ZEND_METHOD(ReflectionParameter, getClass)
2656 {
2657 	reflection_object *intern;
2658 	parameter_reference *param;
2659 	zend_class_entry *ce;
2660 
2661 	if (zend_parse_parameters_none() == FAILURE) {
2662 		RETURN_THROWS();
2663 	}
2664 	GET_REFLECTION_OBJECT_PTR(param);
2665 
2666 	// TODO: This is going to return null for union types, which is rather odd.
2667 	if (ZEND_TYPE_HAS_NAME(param->arg_info->type)) {
2668 		/* Class name is stored as a string, we might also get "self" or "parent"
2669 		 * - For "self", simply use the function scope. If scope is NULL then
2670 		 *   the function is global and thus self does not make any sense
2671 		 *
2672 		 * - For "parent", use the function scope's parent. If scope is NULL then
2673 		 *   the function is global and thus parent does not make any sense.
2674 		 *   If the parent is NULL then the class does not extend anything and
2675 		 *   thus parent does not make any sense, either.
2676 		 *
2677 		 * TODO: Think about moving these checks to the compiler or some sort of
2678 		 * lint-mode.
2679 		 */
2680 		zend_string *class_name;
2681 
2682 		class_name = ZEND_TYPE_NAME(param->arg_info->type);
2683 		if (zend_string_equals_literal_ci(class_name, "self")) {
2684 			ce = param->fptr->common.scope;
2685 			if (!ce) {
2686 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2687 					"Parameter uses \"self\" as type but function is not a class member");
2688 				RETURN_THROWS();
2689 			}
2690 		} else if (zend_string_equals_literal_ci(class_name, "parent")) {
2691 			ce = param->fptr->common.scope;
2692 			if (!ce) {
2693 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2694 					"Parameter uses \"parent\" as type but function is not a class member");
2695 				RETURN_THROWS();
2696 			}
2697 			if (!ce->parent) {
2698 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2699 					"Parameter uses \"parent\" as type although class does not have a parent");
2700 				RETURN_THROWS();
2701 			}
2702 			ce = ce->parent;
2703 		} else {
2704 			ce = zend_lookup_class(class_name);
2705 			if (!ce) {
2706 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2707 					"Class \"%s\" does not exist", ZSTR_VAL(class_name));
2708 				RETURN_THROWS();
2709 			}
2710 		}
2711 		zend_reflection_class_factory(ce, return_value);
2712 	}
2713 }
2714 /* }}} */
2715 
2716 /* {{{ Returns whether parameter has a type */
ZEND_METHOD(ReflectionParameter,hasType)2717 ZEND_METHOD(ReflectionParameter, hasType)
2718 {
2719 	reflection_object *intern;
2720 	parameter_reference *param;
2721 
2722 	if (zend_parse_parameters_none() == FAILURE) {
2723 		RETURN_THROWS();
2724 	}
2725 	GET_REFLECTION_OBJECT_PTR(param);
2726 
2727 	RETVAL_BOOL(ZEND_TYPE_IS_SET(param->arg_info->type));
2728 }
2729 /* }}} */
2730 
2731 /* {{{ Returns the type associated with the parameter */
ZEND_METHOD(ReflectionParameter,getType)2732 ZEND_METHOD(ReflectionParameter, getType)
2733 {
2734 	reflection_object *intern;
2735 	parameter_reference *param;
2736 
2737 	if (zend_parse_parameters_none() == FAILURE) {
2738 		RETURN_THROWS();
2739 	}
2740 	GET_REFLECTION_OBJECT_PTR(param);
2741 
2742 	if (!ZEND_TYPE_IS_SET(param->arg_info->type)) {
2743 		RETURN_NULL();
2744 	}
2745 	reflection_type_factory(param->arg_info->type, return_value, 1);
2746 }
2747 /* }}} */
2748 
2749 /* {{{ Returns whether parameter MUST be an array */
ZEND_METHOD(ReflectionParameter,isArray)2750 ZEND_METHOD(ReflectionParameter, isArray)
2751 {
2752 	reflection_object *intern;
2753 	parameter_reference *param;
2754 	uint32_t type_mask;
2755 
2756 	if (zend_parse_parameters_none() == FAILURE) {
2757 		RETURN_THROWS();
2758 	}
2759 	GET_REFLECTION_OBJECT_PTR(param);
2760 
2761 	/* BC For iterable */
2762 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(param->arg_info->type)) {
2763 		RETURN_FALSE;
2764 	}
2765 
2766 	type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(param->arg_info->type);
2767 	RETVAL_BOOL(type_mask == MAY_BE_ARRAY);
2768 }
2769 /* }}} */
2770 
2771 /* {{{ Returns whether parameter MUST be callable */
ZEND_METHOD(ReflectionParameter,isCallable)2772 ZEND_METHOD(ReflectionParameter, isCallable)
2773 {
2774 	reflection_object *intern;
2775 	parameter_reference *param;
2776 	uint32_t type_mask;
2777 
2778 	if (zend_parse_parameters_none() == FAILURE) {
2779 		RETURN_THROWS();
2780 	}
2781 	GET_REFLECTION_OBJECT_PTR(param);
2782 
2783 	type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(param->arg_info->type);
2784 	RETVAL_BOOL(type_mask == MAY_BE_CALLABLE);
2785 }
2786 /* }}} */
2787 
2788 /* {{{ Returns whether NULL is allowed as this parameters's value */
ZEND_METHOD(ReflectionParameter,allowsNull)2789 ZEND_METHOD(ReflectionParameter, allowsNull)
2790 {
2791 	reflection_object *intern;
2792 	parameter_reference *param;
2793 
2794 	if (zend_parse_parameters_none() == FAILURE) {
2795 		RETURN_THROWS();
2796 	}
2797 	GET_REFLECTION_OBJECT_PTR(param);
2798 
2799 	RETVAL_BOOL(!ZEND_TYPE_IS_SET(param->arg_info->type)
2800 		|| ZEND_TYPE_ALLOW_NULL(param->arg_info->type));
2801 }
2802 /* }}} */
2803 
2804 /* {{{ Returns whether this parameters is passed to by reference */
ZEND_METHOD(ReflectionParameter,isPassedByReference)2805 ZEND_METHOD(ReflectionParameter, isPassedByReference)
2806 {
2807 	reflection_object *intern;
2808 	parameter_reference *param;
2809 
2810 	if (zend_parse_parameters_none() == FAILURE) {
2811 		RETURN_THROWS();
2812 	}
2813 	GET_REFLECTION_OBJECT_PTR(param);
2814 
2815 	RETVAL_BOOL(ZEND_ARG_SEND_MODE(param->arg_info));
2816 }
2817 /* }}} */
2818 
2819 /* {{{ Returns whether this parameter can be passed by value */
ZEND_METHOD(ReflectionParameter,canBePassedByValue)2820 ZEND_METHOD(ReflectionParameter, canBePassedByValue)
2821 {
2822 	reflection_object *intern;
2823 	parameter_reference *param;
2824 
2825 	if (zend_parse_parameters_none() == FAILURE) {
2826 		RETURN_THROWS();
2827 	}
2828 	GET_REFLECTION_OBJECT_PTR(param);
2829 
2830 	/* true if it's ZEND_SEND_BY_VAL or ZEND_SEND_PREFER_REF */
2831 	RETVAL_BOOL(ZEND_ARG_SEND_MODE(param->arg_info) != ZEND_SEND_BY_REF);
2832 }
2833 /* }}} */
2834 
2835 /* {{{ Get parameter attributes. */
ZEND_METHOD(ReflectionParameter,getAttributes)2836 ZEND_METHOD(ReflectionParameter, getAttributes)
2837 {
2838 	reflection_object *intern;
2839 	parameter_reference *param;
2840 
2841 	GET_REFLECTION_OBJECT_PTR(param);
2842 
2843 	HashTable *attributes = param->fptr->common.attributes;
2844 	zend_class_entry *scope = param->fptr->common.scope;
2845 
2846 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2847 		attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER,
2848 		param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL);
2849 }
2850 
2851 /* {{{ Returns whether this parameter is an optional parameter */
ZEND_METHOD(ReflectionParameter,getPosition)2852 ZEND_METHOD(ReflectionParameter, getPosition)
2853 {
2854 	reflection_object *intern;
2855 	parameter_reference *param;
2856 
2857 	if (zend_parse_parameters_none() == FAILURE) {
2858 		RETURN_THROWS();
2859 	}
2860 	GET_REFLECTION_OBJECT_PTR(param);
2861 
2862 	RETVAL_LONG(param->offset);
2863 }
2864 /* }}} */
2865 
2866 /* {{{ Returns whether this parameter is an optional parameter */
ZEND_METHOD(ReflectionParameter,isOptional)2867 ZEND_METHOD(ReflectionParameter, isOptional)
2868 {
2869 	reflection_object *intern;
2870 	parameter_reference *param;
2871 
2872 	if (zend_parse_parameters_none() == FAILURE) {
2873 		RETURN_THROWS();
2874 	}
2875 	GET_REFLECTION_OBJECT_PTR(param);
2876 
2877 	RETVAL_BOOL(!param->required);
2878 }
2879 /* }}} */
2880 
2881 /* {{{ Returns whether the default value of this parameter is available */
ZEND_METHOD(ReflectionParameter,isDefaultValueAvailable)2882 ZEND_METHOD(ReflectionParameter, isDefaultValueAvailable)
2883 {
2884 	reflection_object *intern;
2885 	parameter_reference *param;
2886 
2887 	if (zend_parse_parameters_none() == FAILURE) {
2888 		RETURN_THROWS();
2889 	}
2890 
2891 	GET_REFLECTION_OBJECT_PTR(param);
2892 
2893 	if (param->fptr->type == ZEND_INTERNAL_FUNCTION) {
2894 		RETURN_BOOL(!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)
2895 			&& ((zend_internal_arg_info*) (param->arg_info))->default_value);
2896 	} else {
2897 		zval *default_value = get_default_from_recv((zend_op_array *)param->fptr, param->offset);
2898 		RETURN_BOOL(default_value != NULL);
2899 	}
2900 }
2901 /* }}} */
2902 
2903 /* {{{ Returns the default value of this parameter or throws an exception */
ZEND_METHOD(ReflectionParameter,getDefaultValue)2904 ZEND_METHOD(ReflectionParameter, getDefaultValue)
2905 {
2906 	reflection_object *intern;
2907 	parameter_reference *param;
2908 
2909 	if (zend_parse_parameters_none() == FAILURE) {
2910 		RETURN_THROWS();
2911 	}
2912 
2913 	GET_REFLECTION_OBJECT_PTR(param);
2914 
2915 	if (get_parameter_default(return_value, param) == FAILURE) {
2916 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2917 			"Internal error: Failed to retrieve the default value");
2918 		RETURN_THROWS();
2919 	}
2920 
2921 	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
2922 		zval_update_constant_ex(return_value, param->fptr->common.scope);
2923 	}
2924 }
2925 /* }}} */
2926 
2927 /* {{{ Returns whether the default value of this parameter is constant */
ZEND_METHOD(ReflectionParameter,isDefaultValueConstant)2928 ZEND_METHOD(ReflectionParameter, isDefaultValueConstant)
2929 {
2930 	reflection_object *intern;
2931 	parameter_reference *param;
2932 
2933 	if (zend_parse_parameters_none() == FAILURE) {
2934 		RETURN_THROWS();
2935 	}
2936 
2937 	GET_REFLECTION_OBJECT_PTR(param);
2938 
2939 	zval default_value;
2940 	if (get_parameter_default(&default_value, param) == FAILURE) {
2941 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2942 			"Internal error: Failed to retrieve the default value");
2943 		RETURN_THROWS();
2944 	}
2945 
2946 	if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
2947 		zend_ast *ast = Z_ASTVAL(default_value);
2948 		RETVAL_BOOL(ast->kind == ZEND_AST_CONSTANT
2949 			|| ast->kind == ZEND_AST_CONSTANT_CLASS
2950 			|| ast->kind == ZEND_AST_CLASS_CONST);
2951 	} else {
2952 		RETVAL_FALSE;
2953 	}
2954 
2955 	zval_ptr_dtor_nogc(&default_value);
2956 }
2957 /* }}} */
2958 
2959 /* {{{ Returns the default value's constant name if default value is constant or null */
ZEND_METHOD(ReflectionParameter,getDefaultValueConstantName)2960 ZEND_METHOD(ReflectionParameter, getDefaultValueConstantName)
2961 {
2962 	reflection_object *intern;
2963 	parameter_reference *param;
2964 
2965 	if (zend_parse_parameters_none() == FAILURE) {
2966 		RETURN_THROWS();
2967 	}
2968 
2969 	GET_REFLECTION_OBJECT_PTR(param);
2970 
2971 	zval default_value;
2972 	if (get_parameter_default(&default_value, param) == FAILURE) {
2973 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2974 			"Internal error: Failed to retrieve the default value");
2975 		RETURN_THROWS();
2976 	}
2977 
2978 	if (Z_TYPE(default_value) != IS_CONSTANT_AST) {
2979 		zval_ptr_dtor_nogc(&default_value);
2980 		RETURN_NULL();
2981 	}
2982 
2983 	zend_ast *ast = Z_ASTVAL(default_value);
2984 	if (ast->kind == ZEND_AST_CONSTANT) {
2985 		RETVAL_STR_COPY(zend_ast_get_constant_name(ast));
2986 	} else if (ast->kind == ZEND_AST_CONSTANT_CLASS) {
2987 		RETVAL_STRINGL("__CLASS__", sizeof("__CLASS__")-1);
2988 	} else if (ast->kind == ZEND_AST_CLASS_CONST) {
2989 		zend_string *class_name = zend_ast_get_str(ast->child[0]);
2990 		zend_string *const_name = zend_ast_get_str(ast->child[1]);
2991 		RETVAL_NEW_STR(zend_string_concat3(
2992 			ZSTR_VAL(class_name), ZSTR_LEN(class_name),
2993 			"::", sizeof("::")-1,
2994 			ZSTR_VAL(const_name), ZSTR_LEN(const_name)));
2995 	} else {
2996 		RETVAL_NULL();
2997 	}
2998 	zval_ptr_dtor_nogc(&default_value);
2999 }
3000 
3001 /* {{{ Returns whether this parameter is a variadic parameter */
ZEND_METHOD(ReflectionParameter,isVariadic)3002 ZEND_METHOD(ReflectionParameter, isVariadic)
3003 {
3004 	reflection_object *intern;
3005 	parameter_reference *param;
3006 
3007 	if (zend_parse_parameters_none() == FAILURE) {
3008 		RETURN_THROWS();
3009 	}
3010 	GET_REFLECTION_OBJECT_PTR(param);
3011 
3012 	RETVAL_BOOL(ZEND_ARG_IS_VARIADIC(param->arg_info));
3013 }
3014 /* }}} */
3015 
3016 /* {{{ Returns this constructor parameter has been promoted to a property */
ZEND_METHOD(ReflectionParameter,isPromoted)3017 ZEND_METHOD(ReflectionParameter, isPromoted)
3018 {
3019 	reflection_object *intern;
3020 	parameter_reference *param;
3021 
3022 	if (zend_parse_parameters_none() == FAILURE) {
3023 		RETURN_THROWS();
3024 	}
3025 	GET_REFLECTION_OBJECT_PTR(param);
3026 
3027 	RETVAL_BOOL(ZEND_ARG_IS_PROMOTED(param->arg_info));
3028 }
3029 /* }}} */
3030 
3031 /* {{{ Returns whether parameter MAY be null */
ZEND_METHOD(ReflectionType,allowsNull)3032 ZEND_METHOD(ReflectionType, allowsNull)
3033 {
3034 	reflection_object *intern;
3035 	type_reference *param;
3036 
3037 	if (zend_parse_parameters_none() == FAILURE) {
3038 		RETURN_THROWS();
3039 	}
3040 	GET_REFLECTION_OBJECT_PTR(param);
3041 
3042 	RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->type));
3043 }
3044 /* }}} */
3045 
3046 /* For BC with iterable for named types */
zend_named_reflection_type_to_string(zend_type type)3047 static zend_string *zend_named_reflection_type_to_string(zend_type type) {
3048 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(type)) {
3049 		zend_string *iterable = ZSTR_KNOWN(ZEND_STR_ITERABLE);
3050 		if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_NULL) {
3051 			return zend_string_concat2("?", strlen("?"), ZSTR_VAL(iterable), ZSTR_LEN(iterable));
3052 		}
3053 		return iterable;
3054 	}
3055 	return zend_type_to_string(type);
3056 }
3057 
zend_type_to_string_without_null(zend_type type)3058 static zend_string *zend_type_to_string_without_null(zend_type type) {
3059 	ZEND_TYPE_FULL_MASK(type) &= ~MAY_BE_NULL;
3060 	return zend_named_reflection_type_to_string(type);
3061 }
3062 
3063 /* {{{ Return the text of the type hint */
ZEND_METHOD(ReflectionType,__toString)3064 ZEND_METHOD(ReflectionType, __toString)
3065 {
3066 	reflection_object *intern;
3067 	type_reference *param;
3068 
3069 	if (zend_parse_parameters_none() == FAILURE) {
3070 		RETURN_THROWS();
3071 	}
3072 	GET_REFLECTION_OBJECT_PTR(param);
3073 
3074 	RETURN_STR(zend_named_reflection_type_to_string(param->type));
3075 }
3076 /* }}} */
3077 
3078 /* {{{ Return the name of the type */
ZEND_METHOD(ReflectionNamedType,getName)3079 ZEND_METHOD(ReflectionNamedType, getName)
3080 {
3081 	reflection_object *intern;
3082 	type_reference *param;
3083 
3084 	if (zend_parse_parameters_none() == FAILURE) {
3085 		RETURN_THROWS();
3086 	}
3087 	GET_REFLECTION_OBJECT_PTR(param);
3088 
3089 	if (param->legacy_behavior) {
3090 		RETURN_STR(zend_type_to_string_without_null(param->type));
3091 	}
3092 	RETURN_STR(zend_named_reflection_type_to_string(param->type));
3093 }
3094 /* }}} */
3095 
3096 /* {{{ Returns whether type is a builtin type */
ZEND_METHOD(ReflectionNamedType,isBuiltin)3097 ZEND_METHOD(ReflectionNamedType, isBuiltin)
3098 {
3099 	reflection_object *intern;
3100 	type_reference *param;
3101 
3102 	if (zend_parse_parameters_none() == FAILURE) {
3103 		RETURN_THROWS();
3104 	}
3105 	GET_REFLECTION_OBJECT_PTR(param);
3106 
3107 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(param->type)) {
3108 		RETURN_TRUE;
3109 	}
3110 
3111 	/* Treat "static" as a class type for the purposes of reflection. */
3112 	RETVAL_BOOL(ZEND_TYPE_IS_ONLY_MASK(param->type)
3113 		&& !(ZEND_TYPE_FULL_MASK(param->type) & MAY_BE_STATIC));
3114 }
3115 /* }}} */
3116 
append_type(zval * return_value,zend_type type)3117 static void append_type(zval *return_value, zend_type type) {
3118 	zval reflection_type;
3119 	/* Drop iterable BC bit for type list */
3120 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(type)) {
3121 		ZEND_TYPE_FULL_MASK(type) &= ~_ZEND_TYPE_ITERABLE_BIT;
3122 	}
3123 
3124 	reflection_type_factory(type, &reflection_type, 0);
3125 	zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &reflection_type);
3126 }
3127 
append_type_mask(zval * return_value,uint32_t type_mask)3128 static void append_type_mask(zval *return_value, uint32_t type_mask) {
3129 	append_type(return_value, (zend_type) ZEND_TYPE_INIT_MASK(type_mask));
3130 }
3131 
3132 /* {{{ Returns the types that are part of this union type */
ZEND_METHOD(ReflectionUnionType,getTypes)3133 ZEND_METHOD(ReflectionUnionType, getTypes)
3134 {
3135 	reflection_object *intern;
3136 	type_reference *param;
3137 	uint32_t type_mask;
3138 
3139 	if (zend_parse_parameters_none() == FAILURE) {
3140 		RETURN_THROWS();
3141 	}
3142 	GET_REFLECTION_OBJECT_PTR(param);
3143 
3144 	array_init(return_value);
3145 	if (ZEND_TYPE_HAS_LIST(param->type)) {
3146 		zend_type *list_type;
3147 		ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
3148 			append_type(return_value, *list_type);
3149 		} ZEND_TYPE_LIST_FOREACH_END();
3150 	} else if (ZEND_TYPE_HAS_NAME(param->type)) {
3151 		zend_string *name = ZEND_TYPE_NAME(param->type);
3152 		append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, 0, 0));
3153 	}
3154 
3155 	type_mask = ZEND_TYPE_PURE_MASK(param->type);
3156 	ZEND_ASSERT(!(type_mask & MAY_BE_VOID));
3157 	ZEND_ASSERT(!(type_mask & MAY_BE_NEVER));
3158 	if (type_mask & MAY_BE_STATIC) {
3159 		append_type_mask(return_value, MAY_BE_STATIC);
3160 	}
3161 	if (type_mask & MAY_BE_CALLABLE) {
3162 		append_type_mask(return_value, MAY_BE_CALLABLE);
3163 	}
3164 	if (type_mask & MAY_BE_OBJECT) {
3165 		append_type_mask(return_value, MAY_BE_OBJECT);
3166 	}
3167 	if (type_mask & MAY_BE_ARRAY) {
3168 		append_type_mask(return_value, MAY_BE_ARRAY);
3169 	}
3170 	if (type_mask & MAY_BE_STRING) {
3171 		append_type_mask(return_value, MAY_BE_STRING);
3172 	}
3173 	if (type_mask & MAY_BE_LONG) {
3174 		append_type_mask(return_value, MAY_BE_LONG);
3175 	}
3176 	if (type_mask & MAY_BE_DOUBLE) {
3177 		append_type_mask(return_value, MAY_BE_DOUBLE);
3178 	}
3179 	if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
3180 		append_type_mask(return_value, MAY_BE_BOOL);
3181 	} else if (type_mask & MAY_BE_TRUE) {
3182 		append_type_mask(return_value, MAY_BE_TRUE);
3183 	} else if (type_mask & MAY_BE_FALSE) {
3184 		append_type_mask(return_value, MAY_BE_FALSE);
3185 	}
3186 	if (type_mask & MAY_BE_NULL) {
3187 		append_type_mask(return_value, MAY_BE_NULL);
3188 	}
3189 }
3190 /* }}} */
3191 
3192 /* {{{ Returns the types that are part of this intersection type */
ZEND_METHOD(ReflectionIntersectionType,getTypes)3193 ZEND_METHOD(ReflectionIntersectionType, getTypes)
3194 {
3195 	reflection_object *intern;
3196 	type_reference *param;
3197 	zend_type *list_type;
3198 
3199 	if (zend_parse_parameters_none() == FAILURE) {
3200 		RETURN_THROWS();
3201 	}
3202 	GET_REFLECTION_OBJECT_PTR(param);
3203 
3204 	ZEND_ASSERT(ZEND_TYPE_HAS_LIST(param->type));
3205 
3206 	array_init(return_value);
3207 	ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
3208 		append_type(return_value, *list_type);
3209 	} ZEND_TYPE_LIST_FOREACH_END();
3210 }
3211 /* }}} */
3212 
3213 /* {{{ Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHOD(ReflectionMethod,__construct)3214 ZEND_METHOD(ReflectionMethod, __construct)
3215 {
3216 	zend_object *arg1_obj;
3217 	zend_string *arg1_str;
3218 	zend_string *arg2_str = NULL;
3219 
3220 	zend_object *orig_obj = NULL;
3221 	zend_class_entry *ce = NULL;
3222 	zend_string *class_name = NULL;
3223 	char *method_name;
3224 	size_t method_name_len;
3225 	char *lcname;
3226 
3227 	zval *object;
3228 	reflection_object *intern;
3229 	zend_function *mptr;
3230 
3231 	ZEND_PARSE_PARAMETERS_START(1, 2)
3232 		Z_PARAM_OBJ_OR_STR(arg1_obj, arg1_str)
3233 		Z_PARAM_OPTIONAL
3234 		Z_PARAM_STR_OR_NULL(arg2_str)
3235 	ZEND_PARSE_PARAMETERS_END();
3236 
3237 	if (arg1_obj) {
3238 		if (!arg2_str) {
3239 			zend_argument_value_error(2, "cannot be null when argument #1 ($objectOrMethod) is an object");
3240 			RETURN_THROWS();
3241 		}
3242 
3243 		orig_obj = arg1_obj;
3244 		ce = arg1_obj->ce;
3245 		method_name = ZSTR_VAL(arg2_str);
3246 		method_name_len = ZSTR_LEN(arg2_str);
3247 	} else if (arg2_str) {
3248 		class_name = zend_string_copy(arg1_str);
3249 		method_name = ZSTR_VAL(arg2_str);
3250 		method_name_len = ZSTR_LEN(arg2_str);
3251 	} else {
3252 		char *tmp;
3253 		size_t tmp_len;
3254 		char *name = ZSTR_VAL(arg1_str);
3255 
3256 		if ((tmp = strstr(name, "::")) == NULL) {
3257 			zend_argument_error(reflection_exception_ptr, 1, "must be a valid method name");
3258 			RETURN_THROWS();
3259 		}
3260 		tmp_len = tmp - name;
3261 
3262 		class_name = zend_string_init(name, tmp_len, 0);
3263 		method_name = tmp + 2;
3264 		method_name_len = ZSTR_LEN(arg1_str) - tmp_len - 2;
3265 	}
3266 
3267 	if (class_name) {
3268 		if ((ce = zend_lookup_class(class_name)) == NULL) {
3269 			if (!EG(exception)) {
3270 				zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_name));
3271 			}
3272 			zend_string_release(class_name);
3273 			RETURN_THROWS();
3274 		}
3275 
3276 		zend_string_release(class_name);
3277 	}
3278 
3279 	object = ZEND_THIS;
3280 	intern = Z_REFLECTION_P(object);
3281 
3282 	lcname = zend_str_tolower_dup(method_name, method_name_len);
3283 
3284 	if (ce == zend_ce_closure && orig_obj && (method_name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3285 		&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3286 		&& (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
3287 	{
3288 		/* do nothing, mptr already set */
3289 	} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
3290 		efree(lcname);
3291 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3292 			"Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
3293 		RETURN_THROWS();
3294 	}
3295 	efree(lcname);
3296 
3297 	ZVAL_STR_COPY(reflection_prop_name(object), mptr->common.function_name);
3298 	ZVAL_STR_COPY(reflection_prop_class(object), mptr->common.scope->name);
3299 	intern->ptr = mptr;
3300 	intern->ref_type = REF_TYPE_FUNCTION;
3301 	intern->ce = ce;
3302 }
3303 /* }}} */
3304 
3305 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionMethod,__toString)3306 ZEND_METHOD(ReflectionMethod, __toString)
3307 {
3308 	reflection_object *intern;
3309 	zend_function *mptr;
3310 	smart_str str = {0};
3311 
3312 	if (zend_parse_parameters_none() == FAILURE) {
3313 		RETURN_THROWS();
3314 	}
3315 	GET_REFLECTION_OBJECT_PTR(mptr);
3316 	_function_string(&str, mptr, intern->ce, "");
3317 	RETURN_STR(smart_str_extract(&str));
3318 }
3319 /* }}} */
3320 
3321 /* {{{ Invokes the function */
ZEND_METHOD(ReflectionMethod,getClosure)3322 ZEND_METHOD(ReflectionMethod, getClosure)
3323 {
3324 	reflection_object *intern;
3325 	zval *obj = NULL;
3326 	zend_function *mptr;
3327 
3328 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &obj) == FAILURE) {
3329 		RETURN_THROWS();
3330 	}
3331 
3332 	GET_REFLECTION_OBJECT_PTR(mptr);
3333 
3334 	if (mptr->common.fn_flags & ZEND_ACC_STATIC)  {
3335 		zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
3336 	} else {
3337 		if (!obj) {
3338 			zend_argument_value_error(1, "cannot be null for non-static methods");
3339 			RETURN_THROWS();
3340 		}
3341 
3342 		if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope)) {
3343 			_DO_THROW("Given object is not an instance of the class this method was declared in");
3344 			RETURN_THROWS();
3345 		}
3346 
3347 		/* This is an original closure object and __invoke is to be called. */
3348 		if (Z_OBJCE_P(obj) == zend_ce_closure &&
3349 			(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
3350 		{
3351 			RETURN_OBJ_COPY(Z_OBJ_P(obj));
3352 		} else {
3353 			zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj);
3354 		}
3355 	}
3356 }
3357 /* }}} */
3358 
3359 /* {{{ reflection_method_invoke */
reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS,int variadic)3360 static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic)
3361 {
3362 	zval retval;
3363 	zval *params = NULL, *object;
3364 	HashTable *named_params = NULL;
3365 	reflection_object *intern;
3366 	zend_function *mptr;
3367 	int argc = 0, result;
3368 	zend_fcall_info fci;
3369 	zend_fcall_info_cache fcc;
3370 	zend_class_entry *obj_ce;
3371 
3372 	GET_REFLECTION_OBJECT_PTR(mptr);
3373 
3374 	if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
3375 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3376 			"Trying to invoke abstract method %s::%s()",
3377 			ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3378 		RETURN_THROWS();
3379 	}
3380 
3381 	if (variadic) {
3382 		ZEND_PARSE_PARAMETERS_START(1, -1)
3383 			Z_PARAM_OBJECT_OR_NULL(object)
3384 			Z_PARAM_VARIADIC_WITH_NAMED(params, argc, named_params)
3385 		ZEND_PARSE_PARAMETERS_END();
3386 	} else {
3387 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!h", &object, &named_params) == FAILURE) {
3388 			RETURN_THROWS();
3389 		}
3390 	}
3391 
3392 	/* In case this is a static method, we shouldn't pass an object_ptr
3393 	 * (which is used as calling context aka $this). We can thus ignore the
3394 	 * first parameter.
3395 	 *
3396 	 * Else, we verify that the given object is an instance of the class.
3397 	 */
3398 	if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
3399 		object = NULL;
3400 		obj_ce = mptr->common.scope;
3401 	} else {
3402 		if (!object) {
3403 			zend_throw_exception_ex(reflection_exception_ptr, 0,
3404 				"Trying to invoke non static method %s::%s() without an object",
3405 				ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3406 			RETURN_THROWS();
3407 		}
3408 
3409 		obj_ce = Z_OBJCE_P(object);
3410 
3411 		if (!instanceof_function(obj_ce, mptr->common.scope)) {
3412 			if (!variadic) {
3413 				efree(params);
3414 			}
3415 			_DO_THROW("Given object is not an instance of the class this method was declared in");
3416 			RETURN_THROWS();
3417 		}
3418 	}
3419 
3420 	fci.size = sizeof(fci);
3421 	ZVAL_UNDEF(&fci.function_name);
3422 	fci.object = object ? Z_OBJ_P(object) : NULL;
3423 	fci.retval = &retval;
3424 	fci.param_count = argc;
3425 	fci.params = params;
3426 	fci.named_params = named_params;
3427 
3428 	fcc.function_handler = mptr;
3429 	fcc.called_scope = intern->ce;
3430 	fcc.object = object ? Z_OBJ_P(object) : NULL;
3431 
3432 	/*
3433 	 * Copy the zend_function when calling via handler (e.g. Closure::__invoke())
3434 	 */
3435 	if ((mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
3436 		fcc.function_handler = _copy_function(mptr);
3437 	}
3438 
3439 	result = zend_call_function(&fci, &fcc);
3440 
3441 	if (result == FAILURE) {
3442 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3443 			"Invocation of method %s::%s() failed", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3444 		RETURN_THROWS();
3445 	}
3446 
3447 	if (Z_TYPE(retval) != IS_UNDEF) {
3448 		if (Z_ISREF(retval)) {
3449 			zend_unwrap_reference(&retval);
3450 		}
3451 		ZVAL_COPY_VALUE(return_value, &retval);
3452 	}
3453 }
3454 /* }}} */
3455 
3456 /* {{{ Invokes the method. */
ZEND_METHOD(ReflectionMethod,invoke)3457 ZEND_METHOD(ReflectionMethod, invoke)
3458 {
3459 	reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3460 }
3461 /* }}} */
3462 
3463 /* {{{ Invokes the function and pass its arguments as array. */
ZEND_METHOD(ReflectionMethod,invokeArgs)3464 ZEND_METHOD(ReflectionMethod, invokeArgs)
3465 {
3466 	reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3467 }
3468 /* }}} */
3469 
3470 /* {{{ Returns whether this method is final */
ZEND_METHOD(ReflectionMethod,isFinal)3471 ZEND_METHOD(ReflectionMethod, isFinal)
3472 {
3473 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3474 }
3475 /* }}} */
3476 
3477 /* {{{ Returns whether this method is abstract */
ZEND_METHOD(ReflectionMethod,isAbstract)3478 ZEND_METHOD(ReflectionMethod, isAbstract)
3479 {
3480 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ABSTRACT);
3481 }
3482 /* }}} */
3483 
3484 /* {{{ Returns whether this method is public */
ZEND_METHOD(ReflectionMethod,isPublic)3485 ZEND_METHOD(ReflectionMethod, isPublic)
3486 {
3487 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3488 }
3489 /* }}} */
3490 
3491 /* {{{ Returns whether this method is private */
ZEND_METHOD(ReflectionMethod,isPrivate)3492 ZEND_METHOD(ReflectionMethod, isPrivate)
3493 {
3494 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3495 }
3496 /* }}} */
3497 
3498 /* {{{ Returns whether this method is protected */
ZEND_METHOD(ReflectionMethod,isProtected)3499 ZEND_METHOD(ReflectionMethod, isProtected)
3500 {
3501 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3502 }
3503 /* }}} */
3504 
3505 /* {{{ Returns whether this function is deprecated */
ZEND_METHOD(ReflectionFunctionAbstract,isDeprecated)3506 ZEND_METHOD(ReflectionFunctionAbstract, isDeprecated)
3507 {
3508 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_DEPRECATED);
3509 }
3510 /* }}} */
3511 
3512 /* {{{ Returns whether this function is a generator */
ZEND_METHOD(ReflectionFunctionAbstract,isGenerator)3513 ZEND_METHOD(ReflectionFunctionAbstract, isGenerator)
3514 {
3515 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_GENERATOR);
3516 }
3517 /* }}} */
3518 
3519 /* {{{ Returns whether this function is variadic */
ZEND_METHOD(ReflectionFunctionAbstract,isVariadic)3520 ZEND_METHOD(ReflectionFunctionAbstract, isVariadic)
3521 {
3522 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VARIADIC);
3523 }
3524 /* }}} */
3525 
3526 /* {{{ Returns whether this function is static */
ZEND_METHOD(ReflectionFunctionAbstract,isStatic)3527 ZEND_METHOD(ReflectionFunctionAbstract, isStatic)
3528 {
3529 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
3530 }
3531 /* }}} */
3532 
3533 /* {{{ Returns whether this function is defined in namespace */
ZEND_METHOD(ReflectionFunctionAbstract,inNamespace)3534 ZEND_METHOD(ReflectionFunctionAbstract, inNamespace)
3535 {
3536 	reflection_object *intern;
3537 	zend_function *fptr;
3538 
3539 	if (zend_parse_parameters_none() == FAILURE) {
3540 		RETURN_THROWS();
3541 	}
3542 
3543 	GET_REFLECTION_OBJECT_PTR(fptr);
3544 
3545 	zend_string *name = fptr->common.function_name;
3546 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3547 	RETURN_BOOL(backslash && backslash > ZSTR_VAL(name));
3548 }
3549 /* }}} */
3550 
3551 /* {{{ Returns the name of namespace where this function is defined */
ZEND_METHOD(ReflectionFunctionAbstract,getNamespaceName)3552 ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName)
3553 {
3554 	reflection_object *intern;
3555 	zend_function *fptr;
3556 
3557 	if (zend_parse_parameters_none() == FAILURE) {
3558 		RETURN_THROWS();
3559 	}
3560 
3561 	GET_REFLECTION_OBJECT_PTR(fptr);
3562 
3563 	zend_string *name = fptr->common.function_name;
3564 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3565 	if (backslash && backslash > ZSTR_VAL(name)) {
3566 		RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
3567 	}
3568 	RETURN_EMPTY_STRING();
3569 }
3570 /* }}} */
3571 
3572 /* {{{ Returns the short name of the function (without namespace part) */
ZEND_METHOD(ReflectionFunctionAbstract,getShortName)3573 ZEND_METHOD(ReflectionFunctionAbstract, getShortName)
3574 {
3575 	reflection_object *intern;
3576 	zend_function *fptr;
3577 
3578 	if (zend_parse_parameters_none() == FAILURE) {
3579 		RETURN_THROWS();
3580 	}
3581 
3582 	GET_REFLECTION_OBJECT_PTR(fptr);
3583 
3584 	zend_string *name = fptr->common.function_name;
3585 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3586 	if (backslash && backslash > ZSTR_VAL(name)) {
3587 		RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
3588 	}
3589 	RETURN_STR_COPY(name);
3590 }
3591 /* }}} */
3592 
3593 /* {{{ Return whether the function has a return type */
ZEND_METHOD(ReflectionFunctionAbstract,hasReturnType)3594 ZEND_METHOD(ReflectionFunctionAbstract, hasReturnType)
3595 {
3596 	reflection_object *intern;
3597 	zend_function *fptr;
3598 
3599 	if (zend_parse_parameters_none() == FAILURE) {
3600 		RETURN_THROWS();
3601 	}
3602 
3603 	GET_REFLECTION_OBJECT_PTR(fptr);
3604 
3605 	RETVAL_BOOL((fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && !ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]));
3606 }
3607 /* }}} */
3608 
3609 /* {{{ Returns the return type associated with the function */
ZEND_METHOD(ReflectionFunctionAbstract,getReturnType)3610 ZEND_METHOD(ReflectionFunctionAbstract, getReturnType)
3611 {
3612 	reflection_object *intern;
3613 	zend_function *fptr;
3614 
3615 	if (zend_parse_parameters_none() == FAILURE) {
3616 		RETURN_THROWS();
3617 	}
3618 
3619 	GET_REFLECTION_OBJECT_PTR(fptr);
3620 
3621 	if (!(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])) {
3622 		RETURN_NULL();
3623 	}
3624 
3625 	reflection_type_factory(fptr->common.arg_info[-1].type, return_value, 1);
3626 }
3627 /* }}} */
3628 
3629 /* {{{ Return whether the function has a return type */
ZEND_METHOD(ReflectionFunctionAbstract,hasTentativeReturnType)3630 ZEND_METHOD(ReflectionFunctionAbstract, hasTentativeReturnType)
3631 {
3632 	reflection_object *intern;
3633 	zend_function *fptr;
3634 
3635 	if (zend_parse_parameters_none() == FAILURE) {
3636 		RETURN_THROWS();
3637 	}
3638 
3639 	GET_REFLECTION_OBJECT_PTR(fptr);
3640 
3641 	RETVAL_BOOL(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]));
3642 }
3643 /* }}} */
3644 
3645 /* {{{ Returns the return type associated with the function */
ZEND_METHOD(ReflectionFunctionAbstract,getTentativeReturnType)3646 ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType)
3647 {
3648 	reflection_object *intern;
3649 	zend_function *fptr;
3650 
3651 	if (zend_parse_parameters_none() == FAILURE) {
3652 		RETURN_THROWS();
3653 	}
3654 
3655 	GET_REFLECTION_OBJECT_PTR(fptr);
3656 
3657 	if (!(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || !ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])) {
3658 		RETURN_NULL();
3659 	}
3660 
3661 	reflection_type_factory(fptr->common.arg_info[-1].type, return_value, 1);
3662 }
3663 /* }}} */
3664 
3665 /* {{{ Returns whether this method is the constructor */
ZEND_METHOD(ReflectionMethod,isConstructor)3666 ZEND_METHOD(ReflectionMethod, isConstructor)
3667 {
3668 	reflection_object *intern;
3669 	zend_function *mptr;
3670 
3671 	if (zend_parse_parameters_none() == FAILURE) {
3672 		RETURN_THROWS();
3673 	}
3674 	GET_REFLECTION_OBJECT_PTR(mptr);
3675 	/* we need to check if the ctor is the ctor of the class level we we
3676 	 * looking at since we might be looking at an inherited old style ctor
3677 	 * defined in base class. */
3678 	RETURN_BOOL((mptr->common.fn_flags & ZEND_ACC_CTOR) && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope);
3679 }
3680 /* }}} */
3681 
3682 /* {{{ Returns whether this method is a destructor */
ZEND_METHOD(ReflectionMethod,isDestructor)3683 ZEND_METHOD(ReflectionMethod, isDestructor)
3684 {
3685 	reflection_object *intern;
3686 	zend_function *mptr;
3687 
3688 	if (zend_parse_parameters_none() == FAILURE) {
3689 		RETURN_THROWS();
3690 	}
3691 	GET_REFLECTION_OBJECT_PTR(mptr);
3692 	RETURN_BOOL(zend_string_equals_literal_ci(
3693 		mptr->common.function_name, ZEND_DESTRUCTOR_FUNC_NAME));
3694 }
3695 /* }}} */
3696 
3697 /* {{{ Returns a bitfield of the access modifiers for this method */
ZEND_METHOD(ReflectionMethod,getModifiers)3698 ZEND_METHOD(ReflectionMethod, getModifiers)
3699 {
3700 	reflection_object *intern;
3701 	zend_function *mptr;
3702 	uint32_t keep_flags = ZEND_ACC_PPP_MASK
3703 		| ZEND_ACC_STATIC | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL;
3704 
3705 	if (zend_parse_parameters_none() == FAILURE) {
3706 		RETURN_THROWS();
3707 	}
3708 	GET_REFLECTION_OBJECT_PTR(mptr);
3709 
3710 	RETURN_LONG((mptr->common.fn_flags & keep_flags));
3711 }
3712 /* }}} */
3713 
3714 /* {{{ Get the declaring class */
ZEND_METHOD(ReflectionMethod,getDeclaringClass)3715 ZEND_METHOD(ReflectionMethod, getDeclaringClass)
3716 {
3717 	reflection_object *intern;
3718 	zend_function *mptr;
3719 
3720 	if (zend_parse_parameters_none() == FAILURE) {
3721 		RETURN_THROWS();
3722 	}
3723 
3724 	GET_REFLECTION_OBJECT_PTR(mptr);
3725 
3726 	zend_reflection_class_factory(mptr->common.scope, return_value);
3727 }
3728 /* }}} */
3729 
3730 /* {{{ Returns whether a method has a prototype or not */
ZEND_METHOD(ReflectionMethod,hasPrototype)3731 ZEND_METHOD(ReflectionMethod, hasPrototype)
3732 {
3733     reflection_object *intern;
3734     zend_function *mptr;
3735 
3736     if (zend_parse_parameters_none() == FAILURE) {
3737         RETURN_THROWS();
3738     }
3739 
3740     GET_REFLECTION_OBJECT_PTR(mptr);
3741     RETURN_BOOL(mptr->common.prototype != NULL);
3742 }
3743 /* }}} */
3744 
3745 /* {{{ Get the prototype */
ZEND_METHOD(ReflectionMethod,getPrototype)3746 ZEND_METHOD(ReflectionMethod, getPrototype)
3747 {
3748 	reflection_object *intern;
3749 	zend_function *mptr;
3750 
3751 	if (zend_parse_parameters_none() == FAILURE) {
3752 		RETURN_THROWS();
3753 	}
3754 
3755 	GET_REFLECTION_OBJECT_PTR(mptr);
3756 
3757 	if (!mptr->common.prototype) {
3758 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3759 			"Method %s::%s does not have a prototype", ZSTR_VAL(intern->ce->name), ZSTR_VAL(mptr->common.function_name));
3760 		RETURN_THROWS();
3761 	}
3762 
3763 	reflection_method_factory(mptr->common.prototype->common.scope, mptr->common.prototype, NULL, return_value);
3764 }
3765 /* }}} */
3766 
3767 /* {{{ Sets whether non-public methods can be invoked */
ZEND_METHOD(ReflectionMethod,setAccessible)3768 ZEND_METHOD(ReflectionMethod, setAccessible)
3769 {
3770 	bool visible;
3771 
3772 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
3773 		RETURN_THROWS();
3774 	}
3775 }
3776 /* }}} */
3777 
3778 /* {{{ Constructor. Throws an Exception in case the given class constant does not exist */
ZEND_METHOD(ReflectionClassConstant,__construct)3779 ZEND_METHOD(ReflectionClassConstant, __construct)
3780 {
3781 	zval *object;
3782 	zend_string *classname_str;
3783 	zend_object *classname_obj;
3784 	zend_string *constname;
3785 	reflection_object *intern;
3786 	zend_class_entry *ce;
3787 	zend_class_constant *constant = NULL;
3788 
3789 	ZEND_PARSE_PARAMETERS_START(2, 2)
3790 		Z_PARAM_OBJ_OR_STR(classname_obj, classname_str)
3791 		Z_PARAM_STR(constname)
3792 	ZEND_PARSE_PARAMETERS_END();
3793 
3794 	if (classname_obj) {
3795 		ce = classname_obj->ce;
3796 	} else {
3797 		if ((ce = zend_lookup_class(classname_str)) == NULL) {
3798 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
3799 			RETURN_THROWS();
3800 		}
3801 	}
3802 
3803 	object = ZEND_THIS;
3804 	intern = Z_REFLECTION_P(object);
3805 
3806 	if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
3807 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
3808 		RETURN_THROWS();
3809 	}
3810 
3811 	intern->ptr = constant;
3812 	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
3813 	intern->ce = constant->ce;
3814 	ZVAL_STR_COPY(reflection_prop_name(object), constname);
3815 	ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
3816 }
3817 /* }}} */
3818 
3819 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionClassConstant,__toString)3820 ZEND_METHOD(ReflectionClassConstant, __toString)
3821 {
3822 	reflection_object *intern;
3823 	zend_class_constant *ref;
3824 	smart_str str = {0};
3825 
3826 	if (zend_parse_parameters_none() == FAILURE) {
3827 		RETURN_THROWS();
3828 	}
3829 
3830 	GET_REFLECTION_OBJECT_PTR(ref);
3831 
3832 	zval *name = reflection_prop_name(ZEND_THIS);
3833 	if (Z_ISUNDEF_P(name)) {
3834 		zend_throw_error(NULL,
3835 			"Typed property ReflectionClassConstant::$name "
3836 			"must not be accessed before initialization");
3837 		RETURN_THROWS();
3838 	}
3839 	ZVAL_DEREF(name);
3840 	ZEND_ASSERT(Z_TYPE_P(name) == IS_STRING);
3841 
3842 	_class_const_string(&str, Z_STRVAL_P(name), ref, "");
3843 	RETURN_STR(smart_str_extract(&str));
3844 }
3845 /* }}} */
3846 
3847 /* {{{ Returns the constant' name */
ZEND_METHOD(ReflectionClassConstant,getName)3848 ZEND_METHOD(ReflectionClassConstant, getName)
3849 {
3850 	if (zend_parse_parameters_none() == FAILURE) {
3851 		RETURN_THROWS();
3852 	}
3853 
3854 	zval *name = reflection_prop_name(ZEND_THIS);
3855 	if (Z_ISUNDEF_P(name)) {
3856 		zend_throw_error(NULL,
3857 			"Typed property ReflectionClassConstant::$name "
3858 			"must not be accessed before initialization");
3859 		RETURN_THROWS();
3860 	}
3861 
3862 	RETURN_COPY_DEREF(name);
3863 }
3864 /* }}} */
3865 
_class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)3866 static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
3867 {
3868 	reflection_object *intern;
3869 	zend_class_constant *ref;
3870 
3871 	if (zend_parse_parameters_none() == FAILURE) {
3872 		RETURN_THROWS();
3873 	}
3874 	GET_REFLECTION_OBJECT_PTR(ref);
3875 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(ref) & mask);
3876 }
3877 /* }}} */
3878 
3879 /* {{{ Returns whether this constant is public */
ZEND_METHOD(ReflectionClassConstant,isPublic)3880 ZEND_METHOD(ReflectionClassConstant, isPublic)
3881 {
3882 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3883 }
3884 /* }}} */
3885 
3886 /* {{{ Returns whether this constant is private */
ZEND_METHOD(ReflectionClassConstant,isPrivate)3887 ZEND_METHOD(ReflectionClassConstant, isPrivate)
3888 {
3889 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3890 }
3891 /* }}} */
3892 
3893 /* {{{ Returns whether this constant is protected */
ZEND_METHOD(ReflectionClassConstant,isProtected)3894 ZEND_METHOD(ReflectionClassConstant, isProtected)
3895 {
3896 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3897 }
3898 /* }}} */
3899 
3900 /* Returns whether this constant is final */
ZEND_METHOD(ReflectionClassConstant,isFinal)3901 ZEND_METHOD(ReflectionClassConstant, isFinal)
3902 {
3903 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3904 }
3905 
3906 /* {{{ Returns a bitfield of the access modifiers for this constant */
ZEND_METHOD(ReflectionClassConstant,getModifiers)3907 ZEND_METHOD(ReflectionClassConstant, getModifiers)
3908 {
3909 	reflection_object *intern;
3910 	zend_class_constant *ref;
3911 	uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_PPP_MASK;
3912 
3913 	if (zend_parse_parameters_none() == FAILURE) {
3914 		RETURN_THROWS();
3915 	}
3916 	GET_REFLECTION_OBJECT_PTR(ref);
3917 
3918 	RETURN_LONG(ZEND_CLASS_CONST_FLAGS(ref) & keep_flags);
3919 }
3920 /* }}} */
3921 
3922 /* {{{ Returns this constant's value */
ZEND_METHOD(ReflectionClassConstant,getValue)3923 ZEND_METHOD(ReflectionClassConstant, getValue)
3924 {
3925 	reflection_object *intern;
3926 	zend_class_constant *ref;
3927 
3928 	if (zend_parse_parameters_none() == FAILURE) {
3929 		RETURN_THROWS();
3930 	}
3931 	GET_REFLECTION_OBJECT_PTR(ref);
3932 
3933 	if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
3934 		zval_update_constant_ex(&ref->value, ref->ce);
3935 	}
3936 	ZVAL_COPY_OR_DUP(return_value, &ref->value);
3937 }
3938 /* }}} */
3939 
3940 /* {{{ Get the declaring class */
ZEND_METHOD(ReflectionClassConstant,getDeclaringClass)3941 ZEND_METHOD(ReflectionClassConstant, getDeclaringClass)
3942 {
3943 	reflection_object *intern;
3944 	zend_class_constant *ref;
3945 
3946 	if (zend_parse_parameters_none() == FAILURE) {
3947 		RETURN_THROWS();
3948 	}
3949 	GET_REFLECTION_OBJECT_PTR(ref);
3950 
3951 	zend_reflection_class_factory(ref->ce, return_value);
3952 }
3953 /* }}} */
3954 
3955 /* {{{ Returns the doc comment for this constant */
ZEND_METHOD(ReflectionClassConstant,getDocComment)3956 ZEND_METHOD(ReflectionClassConstant, getDocComment)
3957 {
3958 	reflection_object *intern;
3959 	zend_class_constant *ref;
3960 
3961 	if (zend_parse_parameters_none() == FAILURE) {
3962 		RETURN_THROWS();
3963 	}
3964 	GET_REFLECTION_OBJECT_PTR(ref);
3965 	if (ref->doc_comment) {
3966 		RETURN_STR_COPY(ref->doc_comment);
3967 	}
3968 	RETURN_FALSE;
3969 }
3970 /* }}} */
3971 
3972 /* {{{ Returns the attributes of this constant */
ZEND_METHOD(ReflectionClassConstant,getAttributes)3973 ZEND_METHOD(ReflectionClassConstant, getAttributes)
3974 {
3975 	reflection_object *intern;
3976 	zend_class_constant *ref;
3977 
3978 	GET_REFLECTION_OBJECT_PTR(ref);
3979 
3980 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
3981 		ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST,
3982 		ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL);
3983 }
3984 /* }}} */
3985 
ZEND_METHOD(ReflectionClassConstant,isEnumCase)3986 ZEND_METHOD(ReflectionClassConstant, isEnumCase)
3987 {
3988 	reflection_object *intern;
3989 	zend_class_constant *ref;
3990 
3991 	GET_REFLECTION_OBJECT_PTR(ref);
3992 
3993 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(ref) & ZEND_CLASS_CONST_IS_CASE);
3994 }
3995 
3996 /* {{{ reflection_class_object_ctor */
reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS,int is_object)3997 static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_object)
3998 {
3999 	zval *object;
4000 	zend_string *arg_class = NULL;
4001 	zend_object *arg_obj;
4002 	reflection_object *intern;
4003 	zend_class_entry *ce;
4004 
4005 	if (is_object) {
4006 		ZEND_PARSE_PARAMETERS_START(1, 1)
4007 			Z_PARAM_OBJ(arg_obj)
4008 		ZEND_PARSE_PARAMETERS_END();
4009 	} else {
4010 		ZEND_PARSE_PARAMETERS_START(1, 1)
4011 			Z_PARAM_OBJ_OR_STR(arg_obj, arg_class)
4012 		ZEND_PARSE_PARAMETERS_END();
4013 	}
4014 
4015 	object = ZEND_THIS;
4016 	intern = Z_REFLECTION_P(object);
4017 
4018 	if (arg_obj) {
4019 		ZVAL_STR_COPY(reflection_prop_name(object), arg_obj->ce->name);
4020 		intern->ptr = arg_obj->ce;
4021 		if (is_object) {
4022 			ZVAL_OBJ_COPY(&intern->obj, arg_obj);
4023 		}
4024 	} else {
4025 		if ((ce = zend_lookup_class(arg_class)) == NULL) {
4026 			if (!EG(exception)) {
4027 				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(arg_class));
4028 			}
4029 			RETURN_THROWS();
4030 		}
4031 
4032 		ZVAL_STR_COPY(reflection_prop_name(object), ce->name);
4033 		intern->ptr = ce;
4034 	}
4035 	intern->ref_type = REF_TYPE_OTHER;
4036 }
4037 /* }}} */
4038 
4039 /* {{{ Constructor. Takes a string or an instance as an argument */
ZEND_METHOD(ReflectionClass,__construct)4040 ZEND_METHOD(ReflectionClass, __construct)
4041 {
4042 	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4043 }
4044 /* }}} */
4045 
4046 /* {{{ add_class_vars */
add_class_vars(zend_class_entry * ce,bool statics,zval * return_value)4047 static void add_class_vars(zend_class_entry *ce, bool statics, zval *return_value)
4048 {
4049 	zend_property_info *prop_info;
4050 	zval *prop, prop_copy;
4051 	zend_string *key;
4052 
4053 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
4054 		if (((prop_info->flags & ZEND_ACC_PRIVATE) &&
4055 		     prop_info->ce != ce)) {
4056 			continue;
4057 		}
4058 
4059 		bool is_static = (prop_info->flags & ZEND_ACC_STATIC) != 0;
4060 		if (statics != is_static) {
4061 			continue;
4062 		}
4063 
4064 		prop = property_get_default(prop_info);
4065 		if (Z_ISUNDEF_P(prop)) {
4066 			continue;
4067 		}
4068 
4069 		/* copy: enforce read only access */
4070 		ZVAL_DEREF(prop);
4071 		ZVAL_COPY_OR_DUP(&prop_copy, prop);
4072 
4073 		/* this is necessary to make it able to work with default array
4074 		* properties, returned to user */
4075 		if (Z_TYPE(prop_copy) == IS_CONSTANT_AST) {
4076 			if (UNEXPECTED(zval_update_constant_ex(&prop_copy, ce) != SUCCESS)) {
4077 				return;
4078 			}
4079 		}
4080 
4081 		zend_hash_update(Z_ARRVAL_P(return_value), key, &prop_copy);
4082 	} ZEND_HASH_FOREACH_END();
4083 }
4084 /* }}} */
4085 
4086 /* {{{ Returns an associative array containing all static property values of the class */
ZEND_METHOD(ReflectionClass,getStaticProperties)4087 ZEND_METHOD(ReflectionClass, getStaticProperties)
4088 {
4089 	reflection_object *intern;
4090 	zend_class_entry *ce;
4091 	zend_property_info *prop_info;
4092 	zval *prop;
4093 	zend_string *key;
4094 
4095 	if (zend_parse_parameters_none() == FAILURE) {
4096 		RETURN_THROWS();
4097 	}
4098 
4099 	GET_REFLECTION_OBJECT_PTR(ce);
4100 
4101 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4102 		RETURN_THROWS();
4103 	}
4104 
4105 	if (ce->default_static_members_count && !CE_STATIC_MEMBERS(ce)) {
4106 		zend_class_init_statics(ce);
4107 	}
4108 
4109 	array_init(return_value);
4110 
4111 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
4112 		if (((prop_info->flags & ZEND_ACC_PRIVATE) &&
4113 		     prop_info->ce != ce)) {
4114 			continue;
4115 		}
4116 		if ((prop_info->flags & ZEND_ACC_STATIC) == 0) {
4117 			continue;
4118 		}
4119 
4120 		prop = &CE_STATIC_MEMBERS(ce)[prop_info->offset];
4121 		ZVAL_DEINDIRECT(prop);
4122 
4123 		if (ZEND_TYPE_IS_SET(prop_info->type) && Z_ISUNDEF_P(prop)) {
4124 			continue;
4125 		}
4126 
4127 		/* enforce read only access */
4128 		ZVAL_DEREF(prop);
4129 		Z_TRY_ADDREF_P(prop);
4130 
4131 		zend_hash_update(Z_ARRVAL_P(return_value), key, prop);
4132 	} ZEND_HASH_FOREACH_END();
4133 }
4134 /* }}} */
4135 
4136 /* {{{ Returns the value of a static property */
ZEND_METHOD(ReflectionClass,getStaticPropertyValue)4137 ZEND_METHOD(ReflectionClass, getStaticPropertyValue)
4138 {
4139 	reflection_object *intern;
4140 	zend_class_entry *ce, *old_scope;
4141 	zend_string *name;
4142 	zval *prop, *def_value = NULL;
4143 
4144 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &name, &def_value) == FAILURE) {
4145 		RETURN_THROWS();
4146 	}
4147 
4148 	GET_REFLECTION_OBJECT_PTR(ce);
4149 
4150 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4151 		RETURN_THROWS();
4152 	}
4153 
4154 	old_scope = EG(fake_scope);
4155 	EG(fake_scope) = ce;
4156 	prop = zend_std_get_static_property(ce, name, BP_VAR_IS);
4157 	EG(fake_scope) = old_scope;
4158 
4159 	if (prop) {
4160 		RETURN_COPY_DEREF(prop);
4161 	}
4162 
4163 	if (def_value) {
4164 		RETURN_COPY(def_value);
4165 	}
4166 
4167 	zend_throw_exception_ex(reflection_exception_ptr, 0,
4168 		"Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4169 }
4170 /* }}} */
4171 
4172 /* {{{ Sets the value of a static property */
ZEND_METHOD(ReflectionClass,setStaticPropertyValue)4173 ZEND_METHOD(ReflectionClass, setStaticPropertyValue)
4174 {
4175 	reflection_object *intern;
4176 	zend_class_entry *ce, *old_scope;
4177 	zend_property_info *prop_info;
4178 	zend_string *name;
4179 	zval *variable_ptr, *value;
4180 
4181 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &name, &value) == FAILURE) {
4182 		RETURN_THROWS();
4183 	}
4184 
4185 	GET_REFLECTION_OBJECT_PTR(ce);
4186 
4187 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4188 		RETURN_THROWS();
4189 	}
4190 	old_scope = EG(fake_scope);
4191 	EG(fake_scope) = ce;
4192 	variable_ptr =  zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info);
4193 	EG(fake_scope) = old_scope;
4194 	if (!variable_ptr) {
4195 		zend_clear_exception();
4196 		zend_throw_exception_ex(reflection_exception_ptr, 0,
4197 				"Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4198 		RETURN_THROWS();
4199 	}
4200 
4201 	if (Z_ISREF_P(variable_ptr)) {
4202 		zend_reference *ref = Z_REF_P(variable_ptr);
4203 		variable_ptr = Z_REFVAL_P(variable_ptr);
4204 
4205 		if (!zend_verify_ref_assignable_zval(ref, value, 0)) {
4206 			return;
4207 		}
4208 	}
4209 
4210 	if (ZEND_TYPE_IS_SET(prop_info->type) && !zend_verify_property_type(prop_info, value, 0)) {
4211 		return;
4212 	}
4213 
4214 	zval_ptr_dtor(variable_ptr);
4215 	ZVAL_COPY(variable_ptr, value);
4216 
4217 }
4218 /* }}} */
4219 
4220 /* {{{ Returns an associative array containing copies of all default property values of the class */
ZEND_METHOD(ReflectionClass,getDefaultProperties)4221 ZEND_METHOD(ReflectionClass, getDefaultProperties)
4222 {
4223 	reflection_object *intern;
4224 	zend_class_entry *ce;
4225 
4226 	if (zend_parse_parameters_none() == FAILURE) {
4227 		RETURN_THROWS();
4228 	}
4229 	GET_REFLECTION_OBJECT_PTR(ce);
4230 	array_init(return_value);
4231 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4232 		RETURN_THROWS();
4233 	}
4234 	add_class_vars(ce, 1, return_value);
4235 	add_class_vars(ce, 0, return_value);
4236 }
4237 /* }}} */
4238 
4239 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionClass,__toString)4240 ZEND_METHOD(ReflectionClass, __toString)
4241 {
4242 	reflection_object *intern;
4243 	zend_class_entry *ce;
4244 	smart_str str = {0};
4245 
4246 	if (zend_parse_parameters_none() == FAILURE) {
4247 		RETURN_THROWS();
4248 	}
4249 	GET_REFLECTION_OBJECT_PTR(ce);
4250 	_class_string(&str, ce, &intern->obj, "");
4251 	RETURN_STR(smart_str_extract(&str));
4252 }
4253 /* }}} */
4254 
4255 /* {{{ Returns the class' name */
ZEND_METHOD(ReflectionClass,getName)4256 ZEND_METHOD(ReflectionClass, getName)
4257 {
4258 	reflection_object *intern;
4259 	zend_class_entry *ce;
4260 
4261 	if (zend_parse_parameters_none() == FAILURE) {
4262 		RETURN_THROWS();
4263 	}
4264 
4265 	GET_REFLECTION_OBJECT_PTR(ce);
4266 	RETURN_STR_COPY(ce->name);
4267 }
4268 /* }}} */
4269 
4270 /* {{{ Returns whether this class is an internal class */
ZEND_METHOD(ReflectionClass,isInternal)4271 ZEND_METHOD(ReflectionClass, isInternal)
4272 {
4273 	reflection_object *intern;
4274 	zend_class_entry *ce;
4275 
4276 	if (zend_parse_parameters_none() == FAILURE) {
4277 		RETURN_THROWS();
4278 	}
4279 	GET_REFLECTION_OBJECT_PTR(ce);
4280 	RETURN_BOOL(ce->type == ZEND_INTERNAL_CLASS);
4281 }
4282 /* }}} */
4283 
4284 /* {{{ Returns whether this class is user-defined */
ZEND_METHOD(ReflectionClass,isUserDefined)4285 ZEND_METHOD(ReflectionClass, isUserDefined)
4286 {
4287 	reflection_object *intern;
4288 	zend_class_entry *ce;
4289 
4290 	if (zend_parse_parameters_none() == FAILURE) {
4291 		RETURN_THROWS();
4292 	}
4293 	GET_REFLECTION_OBJECT_PTR(ce);
4294 	RETURN_BOOL(ce->type == ZEND_USER_CLASS);
4295 }
4296 /* }}} */
4297 
4298 /* {{{ Returns whether this class is anonymous */
ZEND_METHOD(ReflectionClass,isAnonymous)4299 ZEND_METHOD(ReflectionClass, isAnonymous)
4300 {
4301 	reflection_object *intern;
4302 	zend_class_entry *ce;
4303 
4304 	if (zend_parse_parameters_none() == FAILURE) {
4305 		RETURN_THROWS();
4306 	}
4307 	GET_REFLECTION_OBJECT_PTR(ce);
4308 	RETURN_BOOL(ce->ce_flags & ZEND_ACC_ANON_CLASS);
4309 }
4310 /* }}} */
4311 
4312 /* {{{ Returns the filename of the file this class was declared in */
ZEND_METHOD(ReflectionClass,getFileName)4313 ZEND_METHOD(ReflectionClass, getFileName)
4314 {
4315 	reflection_object *intern;
4316 	zend_class_entry *ce;
4317 
4318 	if (zend_parse_parameters_none() == FAILURE) {
4319 		RETURN_THROWS();
4320 	}
4321 	GET_REFLECTION_OBJECT_PTR(ce);
4322 	if (ce->type == ZEND_USER_CLASS) {
4323 		RETURN_STR_COPY(ce->info.user.filename);
4324 	}
4325 	RETURN_FALSE;
4326 }
4327 /* }}} */
4328 
4329 /* {{{ Returns the line this class' declaration starts at */
ZEND_METHOD(ReflectionClass,getStartLine)4330 ZEND_METHOD(ReflectionClass, getStartLine)
4331 {
4332 	reflection_object *intern;
4333 	zend_class_entry *ce;
4334 
4335 	if (zend_parse_parameters_none() == FAILURE) {
4336 		RETURN_THROWS();
4337 	}
4338 	GET_REFLECTION_OBJECT_PTR(ce);
4339 	if (ce->type == ZEND_USER_CLASS) {
4340 		RETURN_LONG(ce->info.user.line_start);
4341 	}
4342 	RETURN_FALSE;
4343 }
4344 /* }}} */
4345 
4346 /* {{{ Returns the line this class' declaration ends at */
ZEND_METHOD(ReflectionClass,getEndLine)4347 ZEND_METHOD(ReflectionClass, getEndLine)
4348 {
4349 	reflection_object *intern;
4350 	zend_class_entry *ce;
4351 
4352 	if (zend_parse_parameters_none() == FAILURE) {
4353 		RETURN_THROWS();
4354 	}
4355 	GET_REFLECTION_OBJECT_PTR(ce);
4356 	if (ce->type == ZEND_USER_CLASS) {
4357 		RETURN_LONG(ce->info.user.line_end);
4358 	}
4359 	RETURN_FALSE;
4360 }
4361 /* }}} */
4362 
4363 /* {{{ Returns the doc comment for this class */
ZEND_METHOD(ReflectionClass,getDocComment)4364 ZEND_METHOD(ReflectionClass, getDocComment)
4365 {
4366 	reflection_object *intern;
4367 	zend_class_entry *ce;
4368 
4369 	if (zend_parse_parameters_none() == FAILURE) {
4370 		RETURN_THROWS();
4371 	}
4372 	GET_REFLECTION_OBJECT_PTR(ce);
4373 	if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) {
4374 		RETURN_STR_COPY(ce->info.user.doc_comment);
4375 	}
4376 	RETURN_FALSE;
4377 }
4378 /* }}} */
4379 
4380 /* {{{ Returns the attributes for this class */
ZEND_METHOD(ReflectionClass,getAttributes)4381 ZEND_METHOD(ReflectionClass, getAttributes)
4382 {
4383 	reflection_object *intern;
4384 	zend_class_entry *ce;
4385 
4386 	GET_REFLECTION_OBJECT_PTR(ce);
4387 
4388 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
4389 		ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS,
4390 		ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL);
4391 }
4392 /* }}} */
4393 
4394 /* {{{ Returns the class' constructor if there is one, NULL otherwise */
ZEND_METHOD(ReflectionClass,getConstructor)4395 ZEND_METHOD(ReflectionClass, getConstructor)
4396 {
4397 	reflection_object *intern;
4398 	zend_class_entry *ce;
4399 
4400 	if (zend_parse_parameters_none() == FAILURE) {
4401 		RETURN_THROWS();
4402 	}
4403 	GET_REFLECTION_OBJECT_PTR(ce);
4404 
4405 	if (ce->constructor) {
4406 		reflection_method_factory(ce, ce->constructor, NULL, return_value);
4407 	} else {
4408 		RETURN_NULL();
4409 	}
4410 }
4411 /* }}} */
4412 
4413 /* {{{ Returns whether a method exists or not */
ZEND_METHOD(ReflectionClass,hasMethod)4414 ZEND_METHOD(ReflectionClass, hasMethod)
4415 {
4416 	reflection_object *intern;
4417 	zend_class_entry *ce;
4418 	zend_string *name, *lc_name;
4419 
4420 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4421 		RETURN_THROWS();
4422 	}
4423 
4424 	GET_REFLECTION_OBJECT_PTR(ce);
4425 	lc_name = zend_string_tolower(name);
4426 	RETVAL_BOOL(zend_hash_exists(&ce->function_table, lc_name) || is_closure_invoke(ce, lc_name));
4427 	zend_string_release(lc_name);
4428 }
4429 /* }}} */
4430 
4431 /* {{{ Returns the class' method specified by its name */
ZEND_METHOD(ReflectionClass,getMethod)4432 ZEND_METHOD(ReflectionClass, getMethod)
4433 {
4434 	reflection_object *intern;
4435 	zend_class_entry *ce;
4436 	zend_function *mptr;
4437 	zval obj_tmp;
4438 	zend_string *name, *lc_name;
4439 
4440 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4441 		RETURN_THROWS();
4442 	}
4443 
4444 	GET_REFLECTION_OBJECT_PTR(ce);
4445 	lc_name = zend_string_tolower(name);
4446 	if (!Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name)
4447 		&& (mptr = zend_get_closure_invoke_method(Z_OBJ(intern->obj))) != NULL)
4448 	{
4449 		/* don't assign closure_object since we only reflect the invoke handler
4450 		   method and not the closure definition itself */
4451 		reflection_method_factory(ce, mptr, NULL, return_value);
4452 	} else if (Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name)
4453 		&& object_init_ex(&obj_tmp, ce) == SUCCESS && (mptr = zend_get_closure_invoke_method(Z_OBJ(obj_tmp))) != NULL) {
4454 		/* don't assign closure_object since we only reflect the invoke handler
4455 		   method and not the closure definition itself */
4456 		reflection_method_factory(ce, mptr, NULL, return_value);
4457 		zval_ptr_dtor(&obj_tmp);
4458 	} else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) {
4459 		reflection_method_factory(ce, mptr, NULL, return_value);
4460 	} else {
4461 		zend_throw_exception_ex(reflection_exception_ptr, 0,
4462 				"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4463 	}
4464 	zend_string_release(lc_name);
4465 }
4466 /* }}} */
4467 
4468 /* {{{ _addmethod */
_addmethod(zend_function * mptr,zend_class_entry * ce,HashTable * ht,zend_long filter)4469 static bool _addmethod(zend_function *mptr, zend_class_entry *ce, HashTable *ht, zend_long filter)
4470 {
4471 	if ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) && mptr->common.scope != ce) {
4472 		return 0;
4473 	}
4474 
4475 	if (mptr->common.fn_flags & filter) {
4476 		zval method;
4477 		reflection_method_factory(ce, mptr, NULL, &method);
4478 		zend_hash_next_index_insert_new(ht, &method);
4479 		return 1;
4480 	}
4481 	return 0;
4482 }
4483 /* }}} */
4484 
4485 /* {{{ Returns an array of this class' methods */
ZEND_METHOD(ReflectionClass,getMethods)4486 ZEND_METHOD(ReflectionClass, getMethods)
4487 {
4488 	reflection_object *intern;
4489 	zend_class_entry *ce;
4490 	zend_function *mptr;
4491 	zend_long filter;
4492 	bool filter_is_null = 1;
4493 
4494 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4495 		RETURN_THROWS();
4496 	}
4497 
4498 	if (filter_is_null) {
4499 		filter = ZEND_ACC_PPP_MASK | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL | ZEND_ACC_STATIC;
4500 	}
4501 
4502 	GET_REFLECTION_OBJECT_PTR(ce);
4503 
4504 	array_init(return_value);
4505 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
4506 		_addmethod(mptr, ce, Z_ARRVAL_P(return_value), filter);
4507 	} ZEND_HASH_FOREACH_END();
4508 
4509 	if (instanceof_function(ce, zend_ce_closure)) {
4510 		bool has_obj = Z_TYPE(intern->obj) != IS_UNDEF;
4511 		zval obj_tmp;
4512 		zend_object *obj;
4513 		if (!has_obj) {
4514 			object_init_ex(&obj_tmp, ce);
4515 			obj = Z_OBJ(obj_tmp);
4516 		} else {
4517 			obj = Z_OBJ(intern->obj);
4518 		}
4519 		zend_function *closure = zend_get_closure_invoke_method(obj);
4520 		if (closure) {
4521 			if (!_addmethod(closure, ce, Z_ARRVAL_P(return_value), filter)) {
4522 				_free_function(closure);
4523 			}
4524 		}
4525 		if (!has_obj) {
4526 			zval_ptr_dtor(&obj_tmp);
4527 		}
4528 	}
4529 }
4530 /* }}} */
4531 
4532 /* {{{ Returns whether a property exists or not */
ZEND_METHOD(ReflectionClass,hasProperty)4533 ZEND_METHOD(ReflectionClass, hasProperty)
4534 {
4535 	reflection_object *intern;
4536 	zend_property_info *property_info;
4537 	zend_class_entry *ce;
4538 	zend_string *name;
4539 
4540 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4541 		RETURN_THROWS();
4542 	}
4543 
4544 	GET_REFLECTION_OBJECT_PTR(ce);
4545 	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
4546 		if ((property_info->flags & ZEND_ACC_PRIVATE) && property_info->ce != ce) {
4547 			RETURN_FALSE;
4548 		}
4549 		RETURN_TRUE;
4550 	} else {
4551 		if (Z_TYPE(intern->obj) != IS_UNDEF) {
4552 			if (Z_OBJ_HANDLER(intern->obj, has_property)(Z_OBJ(intern->obj), name, 2, NULL)) {
4553 				RETURN_TRUE;
4554 			}
4555 		}
4556 		RETURN_FALSE;
4557 	}
4558 }
4559 /* }}} */
4560 
4561 /* {{{ Returns the class' property specified by its name */
ZEND_METHOD(ReflectionClass,getProperty)4562 ZEND_METHOD(ReflectionClass, getProperty)
4563 {
4564 	reflection_object *intern;
4565 	zend_class_entry *ce, *ce2;
4566 	zend_property_info *property_info;
4567 	zend_string *name, *classname;
4568 	char *tmp, *str_name;
4569 	size_t classname_len, str_name_len;
4570 
4571 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4572 		RETURN_THROWS();
4573 	}
4574 
4575 	GET_REFLECTION_OBJECT_PTR(ce);
4576 	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
4577 		if (!(property_info->flags & ZEND_ACC_PRIVATE) || property_info->ce == ce) {
4578 			reflection_property_factory(ce, name, property_info, return_value);
4579 			return;
4580 		}
4581 	} else if (Z_TYPE(intern->obj) != IS_UNDEF) {
4582 		/* Check for dynamic properties */
4583 		if (zend_hash_exists(Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj)), name)) {
4584 			reflection_property_factory(ce, name, NULL, return_value);
4585 			return;
4586 		}
4587 	}
4588 	str_name = ZSTR_VAL(name);
4589 	if ((tmp = strstr(ZSTR_VAL(name), "::")) != NULL) {
4590 		classname_len = tmp - ZSTR_VAL(name);
4591 		classname = zend_string_alloc(classname_len, 0);
4592 		zend_str_tolower_copy(ZSTR_VAL(classname), ZSTR_VAL(name), classname_len);
4593 		ZSTR_VAL(classname)[classname_len] = '\0';
4594 		str_name_len = ZSTR_LEN(name) - (classname_len + 2);
4595 		str_name = tmp + 2;
4596 
4597 		ce2 = zend_lookup_class(classname);
4598 		if (!ce2) {
4599 			if (!EG(exception)) {
4600 				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(classname));
4601 			}
4602 			zend_string_release_ex(classname, 0);
4603 			RETURN_THROWS();
4604 		}
4605 		zend_string_release_ex(classname, 0);
4606 
4607 		if (!instanceof_function(ce, ce2)) {
4608 			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));
4609 			RETURN_THROWS();
4610 		}
4611 		ce = ce2;
4612 
4613 		property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len);
4614 		if (property_info != NULL
4615 		 && (!(property_info->flags & ZEND_ACC_PRIVATE)
4616 		  || property_info->ce == ce)) {
4617 			reflection_property_factory_str(ce, str_name, str_name_len, property_info, return_value);
4618 			return;
4619 		}
4620 	}
4621 	zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), str_name);
4622 }
4623 /* }}} */
4624 
4625 /* {{{ _addproperty */
_addproperty(zend_property_info * pptr,zend_string * key,zend_class_entry * ce,HashTable * ht,long filter)4626 static void _addproperty(zend_property_info *pptr, zend_string *key, zend_class_entry *ce, HashTable *ht, long filter)
4627 {
4628 	if ((pptr->flags & ZEND_ACC_PRIVATE) && pptr->ce != ce) {
4629 		return;
4630 	}
4631 
4632 	if (pptr->flags	& filter) {
4633 		zval property;
4634 		reflection_property_factory(ce, key, pptr, &property);
4635 		zend_hash_next_index_insert_new(ht, &property);
4636 	}
4637 }
4638 /* }}} */
4639 
4640 /* {{{ _adddynproperty */
_adddynproperty(zval * ptr,zend_string * key,zend_class_entry * ce,zval * retval)4641 static void _adddynproperty(zval *ptr, zend_string *key, zend_class_entry *ce, zval *retval)
4642 {
4643 	zval property;
4644 
4645 	/* under some circumstances, the properties hash table may contain numeric
4646 	 * properties (e.g. when casting from array). This is a WON'T FIX bug, at
4647 	 * least for the moment. Ignore these */
4648 	if (key == NULL) {
4649 		return;
4650 	}
4651 
4652 	/* Not a dynamic property */
4653 	if (Z_TYPE_P(ptr) == IS_INDIRECT) {
4654 		return;
4655 	}
4656 
4657 	reflection_property_factory(ce, key, NULL, &property);
4658 	add_next_index_zval(retval, &property);
4659 }
4660 /* }}} */
4661 
4662 /* {{{ Returns an array of this class' properties */
ZEND_METHOD(ReflectionClass,getProperties)4663 ZEND_METHOD(ReflectionClass, getProperties)
4664 {
4665 	reflection_object *intern;
4666 	zend_class_entry *ce;
4667 	zend_string *key;
4668 	zend_property_info *prop_info;
4669 	zend_long filter;
4670 	bool filter_is_null = 1;
4671 
4672 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4673 		RETURN_THROWS();
4674 	}
4675 
4676 	if (filter_is_null) {
4677 		filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC;
4678 	}
4679 
4680 	GET_REFLECTION_OBJECT_PTR(ce);
4681 
4682 	array_init(return_value);
4683 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
4684 		_addproperty(prop_info, key, ce, Z_ARRVAL_P(return_value), filter);
4685 	} ZEND_HASH_FOREACH_END();
4686 
4687 	if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0) {
4688 		HashTable *properties = Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj));
4689 		zval *prop;
4690 		ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
4691 			_adddynproperty(prop, key, ce, return_value);
4692 		} ZEND_HASH_FOREACH_END();
4693 	}
4694 }
4695 /* }}} */
4696 
4697 /* {{{ Returns whether a constant exists or not */
ZEND_METHOD(ReflectionClass,hasConstant)4698 ZEND_METHOD(ReflectionClass, hasConstant)
4699 {
4700 	reflection_object *intern;
4701 	zend_class_entry *ce;
4702 	zend_string *name;
4703 
4704 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4705 		RETURN_THROWS();
4706 	}
4707 
4708 	GET_REFLECTION_OBJECT_PTR(ce);
4709 	if (zend_hash_exists(&ce->constants_table, name)) {
4710 		RETURN_TRUE;
4711 	} else {
4712 		RETURN_FALSE;
4713 	}
4714 }
4715 /* }}} */
4716 
4717 /* {{{ Returns an associative array containing this class' constants and their values */
ZEND_METHOD(ReflectionClass,getConstants)4718 ZEND_METHOD(ReflectionClass, getConstants)
4719 {
4720 	reflection_object *intern;
4721 	zend_class_entry *ce;
4722 	zend_string *key;
4723 	zend_class_constant *constant;
4724 	zval val;
4725 	zend_long filter;
4726 	bool filter_is_null = 1;
4727 
4728 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4729 		RETURN_THROWS();
4730 	}
4731 
4732 	if (filter_is_null) {
4733 		filter = ZEND_ACC_PPP_MASK;
4734 	}
4735 
4736 	GET_REFLECTION_OBJECT_PTR(ce);
4737 
4738 	array_init(return_value);
4739 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, constant) {
4740 		if (UNEXPECTED(zval_update_constant_ex(&constant->value, constant->ce) != SUCCESS)) {
4741 			RETURN_THROWS();
4742 		}
4743 
4744 		if (ZEND_CLASS_CONST_FLAGS(constant) & filter) {
4745 			ZVAL_COPY_OR_DUP(&val, &constant->value);
4746 			zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
4747 		}
4748 	} ZEND_HASH_FOREACH_END();
4749 }
4750 /* }}} */
4751 
4752 /* {{{ Returns an associative array containing this class' constants as ReflectionClassConstant objects */
ZEND_METHOD(ReflectionClass,getReflectionConstants)4753 ZEND_METHOD(ReflectionClass, getReflectionConstants)
4754 {
4755 	reflection_object *intern;
4756 	zend_class_entry *ce;
4757 	zend_string *name;
4758 	zend_class_constant *constant;
4759 	zend_long filter;
4760 	bool filter_is_null = 1;
4761 
4762 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4763 		RETURN_THROWS();
4764 	}
4765 
4766 	if (filter_is_null) {
4767 		filter = ZEND_ACC_PPP_MASK;
4768 	}
4769 
4770 	GET_REFLECTION_OBJECT_PTR(ce);
4771 
4772 	array_init(return_value);
4773 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), name, constant) {
4774 		if (ZEND_CLASS_CONST_FLAGS(constant) & filter) {
4775 			zval class_const;
4776 			reflection_class_constant_factory(name, constant, &class_const);
4777 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &class_const);
4778 		}
4779 	} ZEND_HASH_FOREACH_END();
4780 }
4781 /* }}} */
4782 
4783 /* {{{ Returns the class' constant specified by its name */
ZEND_METHOD(ReflectionClass,getConstant)4784 ZEND_METHOD(ReflectionClass, getConstant)
4785 {
4786 	reflection_object *intern;
4787 	zend_class_entry *ce;
4788 	HashTable *constants_table;
4789 	zend_class_constant *c;
4790 	zend_string *name;
4791 
4792 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4793 		RETURN_THROWS();
4794 	}
4795 
4796 	GET_REFLECTION_OBJECT_PTR(ce);
4797 	constants_table = CE_CONSTANTS_TABLE(ce);
4798 	ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) {
4799 		if (UNEXPECTED(zval_update_constant_ex(&c->value, c->ce) != SUCCESS)) {
4800 			RETURN_THROWS();
4801 		}
4802 	} ZEND_HASH_FOREACH_END();
4803 	if ((c = zend_hash_find_ptr(constants_table, name)) == NULL) {
4804 		RETURN_FALSE;
4805 	}
4806 	ZVAL_COPY_OR_DUP(return_value, &c->value);
4807 }
4808 /* }}} */
4809 
4810 /* {{{ Returns the class' constant as ReflectionClassConstant objects */
ZEND_METHOD(ReflectionClass,getReflectionConstant)4811 ZEND_METHOD(ReflectionClass, getReflectionConstant)
4812 {
4813 	reflection_object *intern;
4814 	zend_class_entry *ce;
4815 	zend_class_constant *constant;
4816 	zend_string *name;
4817 
4818 	GET_REFLECTION_OBJECT_PTR(ce);
4819 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4820 		RETURN_THROWS();
4821 	}
4822 
4823 	if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name)) == NULL) {
4824 		RETURN_FALSE;
4825 	}
4826 	reflection_class_constant_factory(name, constant, return_value);
4827 }
4828 /* }}} */
4829 
4830 /* {{{ _class_check_flag */
_class_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)4831 static void _class_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
4832 {
4833 	reflection_object *intern;
4834 	zend_class_entry *ce;
4835 
4836 	if (zend_parse_parameters_none() == FAILURE) {
4837 		RETURN_THROWS();
4838 	}
4839 	GET_REFLECTION_OBJECT_PTR(ce);
4840 	RETVAL_BOOL(ce->ce_flags & mask);
4841 }
4842 /* }}} */
4843 
4844 /* {{{ Returns whether this class is instantiable */
ZEND_METHOD(ReflectionClass,isInstantiable)4845 ZEND_METHOD(ReflectionClass, isInstantiable)
4846 {
4847 	reflection_object *intern;
4848 	zend_class_entry *ce;
4849 
4850 	if (zend_parse_parameters_none() == FAILURE) {
4851 		RETURN_THROWS();
4852 	}
4853 	GET_REFLECTION_OBJECT_PTR(ce);
4854 	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) {
4855 		RETURN_FALSE;
4856 	}
4857 
4858 	/* Basically, the class is instantiable. Though, if there is a constructor
4859 	 * and it is not publicly accessible, it isn't! */
4860 	if (!ce->constructor) {
4861 		RETURN_TRUE;
4862 	}
4863 
4864 	RETURN_BOOL(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC);
4865 }
4866 /* }}} */
4867 
4868 /* {{{ Returns whether this class is cloneable */
ZEND_METHOD(ReflectionClass,isCloneable)4869 ZEND_METHOD(ReflectionClass, isCloneable)
4870 {
4871 	reflection_object *intern;
4872 	zend_class_entry *ce;
4873 	zval obj;
4874 
4875 	if (zend_parse_parameters_none() == FAILURE) {
4876 		RETURN_THROWS();
4877 	}
4878 	GET_REFLECTION_OBJECT_PTR(ce);
4879 	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) {
4880 		RETURN_FALSE;
4881 	}
4882 	if (!Z_ISUNDEF(intern->obj)) {
4883 		if (ce->clone) {
4884 			RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4885 		} else {
4886 			RETURN_BOOL(Z_OBJ_HANDLER(intern->obj, clone_obj) != NULL);
4887 		}
4888 	} else {
4889 		if (ce->clone) {
4890 			RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4891 		} else {
4892 			if (UNEXPECTED(object_init_ex(&obj, ce) != SUCCESS)) {
4893 				return;
4894 			}
4895 			/* We're not calling the constructor, so don't call the destructor either. */
4896 			zend_object_store_ctor_failed(Z_OBJ(obj));
4897 			RETVAL_BOOL(Z_OBJ_HANDLER(obj, clone_obj) != NULL);
4898 			zval_ptr_dtor(&obj);
4899 		}
4900 	}
4901 }
4902 /* }}} */
4903 
4904 /* {{{ Returns whether this is an interface or a class */
ZEND_METHOD(ReflectionClass,isInterface)4905 ZEND_METHOD(ReflectionClass, isInterface)
4906 {
4907 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_INTERFACE);
4908 }
4909 /* }}} */
4910 
4911 /* {{{ Returns whether this is a trait */
ZEND_METHOD(ReflectionClass,isTrait)4912 ZEND_METHOD(ReflectionClass, isTrait)
4913 {
4914 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT);
4915 }
4916 /* }}} */
4917 
ZEND_METHOD(ReflectionClass,isEnum)4918 ZEND_METHOD(ReflectionClass, isEnum)
4919 {
4920 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM);
4921 }
4922 
4923 /* {{{ Returns whether this class is final */
ZEND_METHOD(ReflectionClass,isFinal)4924 ZEND_METHOD(ReflectionClass, isFinal)
4925 {
4926 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
4927 }
4928 /* }}} */
4929 
4930 /* Returns whether this class is readonly */
ZEND_METHOD(ReflectionClass,isReadOnly)4931 ZEND_METHOD(ReflectionClass, isReadOnly)
4932 {
4933 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_READONLY_CLASS);
4934 }
4935 
4936 /* {{{ Returns whether this class is abstract */
ZEND_METHOD(ReflectionClass,isAbstract)4937 ZEND_METHOD(ReflectionClass, isAbstract)
4938 {
4939 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
4940 }
4941 /* }}} */
4942 
4943 /* {{{ Returns a bitfield of the access modifiers for this class */
ZEND_METHOD(ReflectionClass,getModifiers)4944 ZEND_METHOD(ReflectionClass, getModifiers)
4945 {
4946 	reflection_object *intern;
4947 	zend_class_entry *ce;
4948 	uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_READONLY_CLASS;
4949 
4950 	if (zend_parse_parameters_none() == FAILURE) {
4951 		RETURN_THROWS();
4952 	}
4953 	GET_REFLECTION_OBJECT_PTR(ce);
4954 
4955 	RETURN_LONG((ce->ce_flags & keep_flags));
4956 }
4957 /* }}} */
4958 
4959 /* {{{ Returns whether the given object is an instance of this class */
ZEND_METHOD(ReflectionClass,isInstance)4960 ZEND_METHOD(ReflectionClass, isInstance)
4961 {
4962 	reflection_object *intern;
4963 	zend_class_entry *ce;
4964 	zval *object;
4965 
4966 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) {
4967 		RETURN_THROWS();
4968 	}
4969 	GET_REFLECTION_OBJECT_PTR(ce);
4970 	RETURN_BOOL(instanceof_function(Z_OBJCE_P(object), ce));
4971 }
4972 /* }}} */
4973 
4974 /* {{{ Returns an instance of this class */
ZEND_METHOD(ReflectionClass,newInstance)4975 ZEND_METHOD(ReflectionClass, newInstance)
4976 {
4977 	reflection_object *intern;
4978 	zend_class_entry *ce, *old_scope;
4979 	zend_function *constructor;
4980 
4981 	GET_REFLECTION_OBJECT_PTR(ce);
4982 
4983 	if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
4984 		return;
4985 	}
4986 
4987 	old_scope = EG(fake_scope);
4988 	EG(fake_scope) = ce;
4989 	constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
4990 	EG(fake_scope) = old_scope;
4991 
4992 	/* Run the constructor if there is one */
4993 	if (constructor) {
4994 		zval *params;
4995 		int num_args;
4996 		HashTable *named_params;
4997 
4998 		if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
4999 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
5000 			zval_ptr_dtor(return_value);
5001 			RETURN_NULL();
5002 		}
5003 
5004 		ZEND_PARSE_PARAMETERS_START(0, -1)
5005 			Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params)
5006 		ZEND_PARSE_PARAMETERS_END();
5007 
5008 		zend_call_known_function(
5009 			constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL,
5010 			num_args, params, named_params);
5011 
5012 		if (EG(exception)) {
5013 			zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5014 		}
5015 	} else if (ZEND_NUM_ARGS()) {
5016 		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));
5017 	}
5018 }
5019 /* }}} */
5020 
5021 /* {{{ Returns an instance of this class without invoking its constructor */
ZEND_METHOD(ReflectionClass,newInstanceWithoutConstructor)5022 ZEND_METHOD(ReflectionClass, newInstanceWithoutConstructor)
5023 {
5024 	reflection_object *intern;
5025 	zend_class_entry *ce;
5026 
5027 	GET_REFLECTION_OBJECT_PTR(ce);
5028 
5029 	if (zend_parse_parameters_none() == FAILURE) {
5030 		RETURN_THROWS();
5031 	}
5032 
5033 	if (ce->type == ZEND_INTERNAL_CLASS
5034 			&& ce->create_object != NULL && (ce->ce_flags & ZEND_ACC_FINAL)) {
5035 		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));
5036 		RETURN_THROWS();
5037 	}
5038 
5039 	object_init_ex(return_value, ce);
5040 }
5041 /* }}} */
5042 
5043 /* {{{ Returns an instance of this class */
ZEND_METHOD(ReflectionClass,newInstanceArgs)5044 ZEND_METHOD(ReflectionClass, newInstanceArgs)
5045 {
5046 	reflection_object *intern;
5047 	zend_class_entry *ce, *old_scope;
5048 	int argc = 0;
5049 	HashTable *args = NULL;
5050 	zend_function *constructor;
5051 
5052 	GET_REFLECTION_OBJECT_PTR(ce);
5053 
5054 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|h", &args) == FAILURE) {
5055 		RETURN_THROWS();
5056 	}
5057 
5058 	if (args) {
5059 		argc = zend_hash_num_elements(args);
5060 	}
5061 
5062 	if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
5063 		return;
5064 	}
5065 
5066 	old_scope = EG(fake_scope);
5067 	EG(fake_scope) = ce;
5068 	constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
5069 	EG(fake_scope) = old_scope;
5070 
5071 	/* Run the constructor if there is one */
5072 	if (constructor) {
5073 		if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
5074 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
5075 			zval_ptr_dtor(return_value);
5076 			RETURN_NULL();
5077 		}
5078 
5079 		zend_call_known_function(
5080 			constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, 0, NULL, args);
5081 
5082 		if (EG(exception)) {
5083 			zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5084 		}
5085 	} else if (argc) {
5086 		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));
5087 	}
5088 }
5089 /* }}} */
5090 
5091 /* {{{ Returns an array of interfaces this class implements */
ZEND_METHOD(ReflectionClass,getInterfaces)5092 ZEND_METHOD(ReflectionClass, getInterfaces)
5093 {
5094 	reflection_object *intern;
5095 	zend_class_entry *ce;
5096 
5097 	if (zend_parse_parameters_none() == FAILURE) {
5098 		RETURN_THROWS();
5099 	}
5100 	GET_REFLECTION_OBJECT_PTR(ce);
5101 
5102 	if (ce->num_interfaces) {
5103 		uint32_t i;
5104 
5105 		ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
5106 		array_init(return_value);
5107 		for (i=0; i < ce->num_interfaces; i++) {
5108 			zval interface;
5109 			zend_reflection_class_factory(ce->interfaces[i], &interface);
5110 			zend_hash_update(Z_ARRVAL_P(return_value), ce->interfaces[i]->name, &interface);
5111 		}
5112 	} else {
5113 		RETURN_EMPTY_ARRAY();
5114 	}
5115 }
5116 /* }}} */
5117 
5118 /* {{{ Returns an array of names of interfaces this class implements */
ZEND_METHOD(ReflectionClass,getInterfaceNames)5119 ZEND_METHOD(ReflectionClass, getInterfaceNames)
5120 {
5121 	reflection_object *intern;
5122 	zend_class_entry *ce;
5123 	uint32_t i;
5124 
5125 	if (zend_parse_parameters_none() == FAILURE) {
5126 		RETURN_THROWS();
5127 	}
5128 	GET_REFLECTION_OBJECT_PTR(ce);
5129 
5130 	if (!ce->num_interfaces) {
5131 		/* Return an empty array if this class implements no interfaces */
5132 		RETURN_EMPTY_ARRAY();
5133 	}
5134 
5135 	ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
5136 	array_init(return_value);
5137 
5138 	for (i=0; i < ce->num_interfaces; i++) {
5139 		add_next_index_str(return_value, zend_string_copy(ce->interfaces[i]->name));
5140 	}
5141 }
5142 /* }}} */
5143 
5144 /* {{{ Returns an array of traits used by this class */
ZEND_METHOD(ReflectionClass,getTraits)5145 ZEND_METHOD(ReflectionClass, getTraits)
5146 {
5147 	reflection_object *intern;
5148 	zend_class_entry *ce;
5149 	uint32_t i;
5150 
5151 	if (zend_parse_parameters_none() == FAILURE) {
5152 		RETURN_THROWS();
5153 	}
5154 	GET_REFLECTION_OBJECT_PTR(ce);
5155 
5156 	if (!ce->num_traits) {
5157 		RETURN_EMPTY_ARRAY();
5158 	}
5159 
5160 	array_init(return_value);
5161 
5162 	for (i=0; i < ce->num_traits; i++) {
5163 		zval trait;
5164 		zend_class_entry *trait_ce;
5165 
5166 		trait_ce = zend_fetch_class_by_name(ce->trait_names[i].name,
5167 			ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
5168 		ZEND_ASSERT(trait_ce);
5169 		zend_reflection_class_factory(trait_ce, &trait);
5170 		zend_hash_update(Z_ARRVAL_P(return_value), ce->trait_names[i].name, &trait);
5171 	}
5172 }
5173 /* }}} */
5174 
5175 /* {{{ Returns an array of names of traits used by this class */
ZEND_METHOD(ReflectionClass,getTraitNames)5176 ZEND_METHOD(ReflectionClass, getTraitNames)
5177 {
5178 	reflection_object *intern;
5179 	zend_class_entry *ce;
5180 	uint32_t i;
5181 
5182 	if (zend_parse_parameters_none() == FAILURE) {
5183 		RETURN_THROWS();
5184 	}
5185 	GET_REFLECTION_OBJECT_PTR(ce);
5186 
5187 	if (!ce->num_traits) {
5188 		RETURN_EMPTY_ARRAY();
5189 	}
5190 
5191 	array_init(return_value);
5192 
5193 	for (i=0; i < ce->num_traits; i++) {
5194 		add_next_index_str(return_value, zend_string_copy(ce->trait_names[i].name));
5195 	}
5196 }
5197 /* }}} */
5198 
5199 /* {{{ Returns an array of trait aliases */
ZEND_METHOD(ReflectionClass,getTraitAliases)5200 ZEND_METHOD(ReflectionClass, getTraitAliases)
5201 {
5202 	reflection_object *intern;
5203 	zend_class_entry *ce;
5204 
5205 	if (zend_parse_parameters_none() == FAILURE) {
5206 		RETURN_THROWS();
5207 	}
5208 	GET_REFLECTION_OBJECT_PTR(ce);
5209 
5210 
5211 	if (ce->trait_aliases) {
5212 		uint32_t i = 0;
5213 
5214 		array_init(return_value);
5215 		while (ce->trait_aliases[i]) {
5216 			zend_string *mname;
5217 			zend_trait_method_reference *cur_ref = &ce->trait_aliases[i]->trait_method;
5218 
5219 			if (ce->trait_aliases[i]->alias) {
5220 				zend_string *class_name = cur_ref->class_name;
5221 
5222 				if (!class_name) {
5223 					uint32_t j = 0;
5224 					zend_string *lcname = zend_string_tolower(cur_ref->method_name);
5225 
5226 					for (j = 0; j < ce->num_traits; j++) {
5227 						zend_class_entry *trait =
5228 							zend_hash_find_ptr(CG(class_table), ce->trait_names[j].lc_name);
5229 						ZEND_ASSERT(trait && "Trait must exist");
5230 						if (zend_hash_exists(&trait->function_table, lcname)) {
5231 							class_name = trait->name;
5232 							break;
5233 						}
5234 					}
5235 					zend_string_release_ex(lcname, 0);
5236 					ZEND_ASSERT(class_name != NULL);
5237 				}
5238 
5239 				mname = zend_string_alloc(ZSTR_LEN(class_name) + ZSTR_LEN(cur_ref->method_name) + 2, 0);
5240 				snprintf(ZSTR_VAL(mname), ZSTR_LEN(mname) + 1, "%s::%s", ZSTR_VAL(class_name), ZSTR_VAL(cur_ref->method_name));
5241 				add_assoc_str_ex(return_value, ZSTR_VAL(ce->trait_aliases[i]->alias), ZSTR_LEN(ce->trait_aliases[i]->alias), mname);
5242 			}
5243 			i++;
5244 		}
5245 	} else {
5246 		RETURN_EMPTY_ARRAY();
5247 	}
5248 }
5249 /* }}} */
5250 
5251 /* {{{ Returns the class' parent class, or, if none exists, FALSE */
ZEND_METHOD(ReflectionClass,getParentClass)5252 ZEND_METHOD(ReflectionClass, getParentClass)
5253 {
5254 	reflection_object *intern;
5255 	zend_class_entry *ce;
5256 
5257 	if (zend_parse_parameters_none() == FAILURE) {
5258 		RETURN_THROWS();
5259 	}
5260 	GET_REFLECTION_OBJECT_PTR(ce);
5261 
5262 	if (ce->parent) {
5263 		zend_reflection_class_factory(ce->parent, return_value);
5264 	} else {
5265 		RETURN_FALSE;
5266 	}
5267 }
5268 /* }}} */
5269 
5270 /* {{{ Returns whether this class is a subclass of another class */
ZEND_METHOD(ReflectionClass,isSubclassOf)5271 ZEND_METHOD(ReflectionClass, isSubclassOf)
5272 {
5273 	reflection_object *intern, *argument;
5274 	zend_class_entry *ce, *class_ce;
5275 	zend_string *class_str;
5276 	zend_object *class_obj;
5277 
5278 	ZEND_PARSE_PARAMETERS_START(1, 1)
5279 		Z_PARAM_OBJ_OF_CLASS_OR_STR(class_obj, reflection_class_ptr, class_str)
5280 	ZEND_PARSE_PARAMETERS_END();
5281 
5282 	if (class_obj) {
5283 		argument = reflection_object_from_obj(class_obj);
5284 		if (argument->ptr == NULL) {
5285 			zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5286 			RETURN_THROWS();
5287 		}
5288 
5289 		class_ce = argument->ptr;
5290 	} else {
5291 		if ((class_ce = zend_lookup_class(class_str)) == NULL) {
5292 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_str));
5293 			RETURN_THROWS();
5294 		}
5295 	}
5296 
5297 	GET_REFLECTION_OBJECT_PTR(ce);
5298 
5299 	RETURN_BOOL((ce != class_ce && instanceof_function(ce, class_ce)));
5300 }
5301 /* }}} */
5302 
5303 /* {{{ Returns whether this class is a subclass of another class */
ZEND_METHOD(ReflectionClass,implementsInterface)5304 ZEND_METHOD(ReflectionClass, implementsInterface)
5305 {
5306 	reflection_object *intern, *argument;
5307 	zend_string *interface_str;
5308 	zend_class_entry *ce, *interface_ce;
5309 	zend_object *interface_obj;
5310 
5311 	ZEND_PARSE_PARAMETERS_START(1, 1)
5312 		Z_PARAM_OBJ_OF_CLASS_OR_STR(interface_obj, reflection_class_ptr, interface_str)
5313 	ZEND_PARSE_PARAMETERS_END();
5314 
5315 	if (interface_obj) {
5316 		argument = reflection_object_from_obj(interface_obj);
5317 		if (argument->ptr == NULL) {
5318 			zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5319 			RETURN_THROWS();
5320 		}
5321 
5322 		interface_ce = argument->ptr;
5323 	} else {
5324 		if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
5325 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Interface \"%s\" does not exist", ZSTR_VAL(interface_str));
5326 			RETURN_THROWS();
5327 		}
5328 	}
5329 
5330 	if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) {
5331 		zend_throw_exception_ex(reflection_exception_ptr, 0, "%s is not an interface", ZSTR_VAL(interface_ce->name));
5332 		RETURN_THROWS();
5333 	}
5334 
5335 	GET_REFLECTION_OBJECT_PTR(ce);
5336 
5337 	RETURN_BOOL(instanceof_function(ce, interface_ce));
5338 }
5339 /* }}} */
5340 
5341 /* {{{ Returns whether this class is iterable (can be used inside foreach) */
ZEND_METHOD(ReflectionClass,isIterable)5342 ZEND_METHOD(ReflectionClass, isIterable)
5343 {
5344 	reflection_object *intern;
5345 	zend_class_entry *ce;
5346 
5347 	if (zend_parse_parameters_none() == FAILURE) {
5348 		RETURN_THROWS();
5349 	}
5350 
5351 	GET_REFLECTION_OBJECT_PTR(ce);
5352 
5353 	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS |
5354 	                    ZEND_ACC_TRAIT     | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
5355 		RETURN_FALSE;
5356 	}
5357 
5358 	RETURN_BOOL(ce->get_iterator || instanceof_function(ce, zend_ce_traversable));
5359 }
5360 /* }}} */
5361 
5362 /* {{{ Returns NULL or the extension the class belongs to */
ZEND_METHOD(ReflectionClass,getExtension)5363 ZEND_METHOD(ReflectionClass, getExtension)
5364 {
5365 	reflection_object *intern;
5366 	zend_class_entry *ce;
5367 
5368 	if (zend_parse_parameters_none() == FAILURE) {
5369 		RETURN_THROWS();
5370 	}
5371 
5372 	GET_REFLECTION_OBJECT_PTR(ce);
5373 
5374 	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5375 		reflection_extension_factory(return_value, ce->info.internal.module->name);
5376 	}
5377 }
5378 /* }}} */
5379 
5380 /* {{{ Returns false or the name of the extension the class belongs to */
ZEND_METHOD(ReflectionClass,getExtensionName)5381 ZEND_METHOD(ReflectionClass, getExtensionName)
5382 {
5383 	reflection_object *intern;
5384 	zend_class_entry *ce;
5385 
5386 	if (zend_parse_parameters_none() == FAILURE) {
5387 		RETURN_THROWS();
5388 	}
5389 
5390 	GET_REFLECTION_OBJECT_PTR(ce);
5391 
5392 	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5393 		RETURN_STRING(ce->info.internal.module->name);
5394 	} else {
5395 		RETURN_FALSE;
5396 	}
5397 }
5398 /* }}} */
5399 
5400 /* {{{ Returns whether this class is defined in namespace */
ZEND_METHOD(ReflectionClass,inNamespace)5401 ZEND_METHOD(ReflectionClass, inNamespace)
5402 {
5403 	reflection_object *intern;
5404 	zend_class_entry *ce;
5405 
5406 	if (zend_parse_parameters_none() == FAILURE) {
5407 		RETURN_THROWS();
5408 	}
5409 
5410 	GET_REFLECTION_OBJECT_PTR(ce);
5411 
5412 	zend_string *name = ce->name;
5413 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5414 	RETURN_BOOL(backslash && backslash > ZSTR_VAL(name));
5415 }
5416 /* }}} */
5417 
5418 /* {{{ Returns the name of namespace where this class is defined */
ZEND_METHOD(ReflectionClass,getNamespaceName)5419 ZEND_METHOD(ReflectionClass, getNamespaceName)
5420 {
5421 	reflection_object *intern;
5422 	zend_class_entry *ce;
5423 
5424 	if (zend_parse_parameters_none() == FAILURE) {
5425 		RETURN_THROWS();
5426 	}
5427 
5428 	GET_REFLECTION_OBJECT_PTR(ce);
5429 
5430 	zend_string *name = ce->name;
5431 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5432 	if (backslash && backslash > ZSTR_VAL(name)) {
5433 		RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
5434 	}
5435 	RETURN_EMPTY_STRING();
5436 }
5437 /* }}} */
5438 
5439 /* {{{ Returns the short name of the class (without namespace part) */
ZEND_METHOD(ReflectionClass,getShortName)5440 ZEND_METHOD(ReflectionClass, getShortName)
5441 {
5442 	reflection_object *intern;
5443 	zend_class_entry *ce;
5444 
5445 	if (zend_parse_parameters_none() == FAILURE) {
5446 		RETURN_THROWS();
5447 	}
5448 
5449 	GET_REFLECTION_OBJECT_PTR(ce);
5450 
5451 	zend_string *name = ce->name;
5452 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5453 	if (backslash && backslash > ZSTR_VAL(name)) {
5454 		RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
5455 	}
5456 	RETURN_STR_COPY(name);
5457 }
5458 /* }}} */
5459 
5460 /* {{{ Constructor. Takes an instance as an argument */
ZEND_METHOD(ReflectionObject,__construct)5461 ZEND_METHOD(ReflectionObject, __construct)
5462 {
5463 	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
5464 }
5465 /* }}} */
5466 
5467 /* {{{ Constructor. Throws an Exception in case the given property does not exist */
ZEND_METHOD(ReflectionProperty,__construct)5468 ZEND_METHOD(ReflectionProperty, __construct)
5469 {
5470 	zend_string *classname_str;
5471 	zend_object *classname_obj;
5472 	zend_string *name;
5473 	int dynam_prop = 0;
5474 	zval *object;
5475 	reflection_object *intern;
5476 	zend_class_entry *ce;
5477 	zend_property_info *property_info = NULL;
5478 	property_reference *reference;
5479 
5480 	ZEND_PARSE_PARAMETERS_START(2, 2)
5481 		Z_PARAM_OBJ_OR_STR(classname_obj, classname_str)
5482 		Z_PARAM_STR(name)
5483 	ZEND_PARSE_PARAMETERS_END();
5484 
5485 	object = ZEND_THIS;
5486 	intern = Z_REFLECTION_P(object);
5487 
5488 	if (classname_obj) {
5489 		ce = classname_obj->ce;
5490 	} else {
5491 		if ((ce = zend_lookup_class(classname_str)) == NULL) {
5492 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
5493 			RETURN_THROWS();
5494 		}
5495 	}
5496 
5497 	property_info = zend_hash_find_ptr(&ce->properties_info, name);
5498 	if (property_info == NULL
5499 	 || ((property_info->flags & ZEND_ACC_PRIVATE)
5500 	  && property_info->ce != ce)) {
5501 		/* Check for dynamic properties */
5502 		if (property_info == NULL && classname_obj) {
5503 			if (zend_hash_exists(classname_obj->handlers->get_properties(classname_obj), name)) {
5504 				dynam_prop = 1;
5505 			}
5506 		}
5507 		if (dynam_prop == 0) {
5508 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
5509 			RETURN_THROWS();
5510 		}
5511 	}
5512 
5513 	ZVAL_STR_COPY(reflection_prop_name(object), name);
5514 	if (dynam_prop == 0) {
5515 		ZVAL_STR_COPY(reflection_prop_class(object), property_info->ce->name);
5516 	} else {
5517 		ZVAL_STR_COPY(reflection_prop_class(object), ce->name);
5518 	}
5519 
5520 	reference = (property_reference*) emalloc(sizeof(property_reference));
5521 	reference->prop = dynam_prop ? NULL : property_info;
5522 	reference->unmangled_name = zend_string_copy(name);
5523 	intern->ptr = reference;
5524 	intern->ref_type = REF_TYPE_PROPERTY;
5525 	intern->ce = ce;
5526 }
5527 /* }}} */
5528 
5529 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionProperty,__toString)5530 ZEND_METHOD(ReflectionProperty, __toString)
5531 {
5532 	reflection_object *intern;
5533 	property_reference *ref;
5534 	smart_str str = {0};
5535 
5536 	if (zend_parse_parameters_none() == FAILURE) {
5537 		RETURN_THROWS();
5538 	}
5539 	GET_REFLECTION_OBJECT_PTR(ref);
5540 	_property_string(&str, ref->prop, ZSTR_VAL(ref->unmangled_name), "");
5541 	RETURN_STR(smart_str_extract(&str));
5542 }
5543 /* }}} */
5544 
5545 /* {{{ Returns the class' name */
ZEND_METHOD(ReflectionProperty,getName)5546 ZEND_METHOD(ReflectionProperty, getName)
5547 {
5548 	reflection_object *intern;
5549 	property_reference *ref;
5550 
5551 	if (zend_parse_parameters_none() == FAILURE) {
5552 		RETURN_THROWS();
5553 	}
5554 
5555 	GET_REFLECTION_OBJECT_PTR(ref);
5556 	RETURN_STR_COPY(ref->unmangled_name);
5557 }
5558 /* }}} */
5559 
_property_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)5560 static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
5561 {
5562 	reflection_object *intern;
5563 	property_reference *ref;
5564 
5565 	if (zend_parse_parameters_none() == FAILURE) {
5566 		RETURN_THROWS();
5567 	}
5568 	GET_REFLECTION_OBJECT_PTR(ref);
5569 	RETURN_BOOL(prop_get_flags(ref) & mask);
5570 }
5571 /* }}} */
5572 
5573 /* {{{ Returns whether this property is public */
ZEND_METHOD(ReflectionProperty,isPublic)5574 ZEND_METHOD(ReflectionProperty, isPublic)
5575 {
5576 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
5577 }
5578 /* }}} */
5579 
5580 /* {{{ Returns whether this property is private */
ZEND_METHOD(ReflectionProperty,isPrivate)5581 ZEND_METHOD(ReflectionProperty, isPrivate)
5582 {
5583 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
5584 }
5585 /* }}} */
5586 
5587 /* {{{ Returns whether this property is protected */
ZEND_METHOD(ReflectionProperty,isProtected)5588 ZEND_METHOD(ReflectionProperty, isProtected)
5589 {
5590 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
5591 }
5592 /* }}} */
5593 
5594 /* {{{ Returns whether this property is static */
ZEND_METHOD(ReflectionProperty,isStatic)5595 ZEND_METHOD(ReflectionProperty, isStatic)
5596 {
5597 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
5598 }
5599 /* }}} */
5600 
ZEND_METHOD(ReflectionProperty,isReadOnly)5601 ZEND_METHOD(ReflectionProperty, isReadOnly)
5602 {
5603 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_READONLY);
5604 }
5605 
5606 /* {{{ Returns whether this property is default (declared at compilation time). */
ZEND_METHOD(ReflectionProperty,isDefault)5607 ZEND_METHOD(ReflectionProperty, isDefault)
5608 {
5609 	reflection_object *intern;
5610 	property_reference *ref;
5611 
5612 	if (zend_parse_parameters_none() == FAILURE) {
5613 		RETURN_THROWS();
5614 	}
5615 	GET_REFLECTION_OBJECT_PTR(ref);
5616 	RETURN_BOOL(ref->prop != NULL);
5617 }
5618 /* }}} */
5619 
5620 /* {{{ Returns whether this property has been promoted from a constructor */
ZEND_METHOD(ReflectionProperty,isPromoted)5621 ZEND_METHOD(ReflectionProperty, isPromoted)
5622 {
5623 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROMOTED);
5624 }
5625 /* }}} */
5626 
5627 /* {{{ Returns a bitfield of the access modifiers for this property */
ZEND_METHOD(ReflectionProperty,getModifiers)5628 ZEND_METHOD(ReflectionProperty, getModifiers)
5629 {
5630 	reflection_object *intern;
5631 	property_reference *ref;
5632 	uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
5633 
5634 	if (zend_parse_parameters_none() == FAILURE) {
5635 		RETURN_THROWS();
5636 	}
5637 	GET_REFLECTION_OBJECT_PTR(ref);
5638 
5639 	RETURN_LONG(prop_get_flags(ref) & keep_flags);
5640 }
5641 /* }}} */
5642 
5643 /* {{{ Returns this property's value */
ZEND_METHOD(ReflectionProperty,getValue)5644 ZEND_METHOD(ReflectionProperty, getValue)
5645 {
5646 	reflection_object *intern;
5647 	property_reference *ref;
5648 	zval *object = NULL;
5649 	zval *member_p = NULL;
5650 
5651 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) {
5652 		RETURN_THROWS();
5653 	}
5654 
5655 	GET_REFLECTION_OBJECT_PTR(ref);
5656 
5657 	if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5658 		member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 0);
5659 		if (member_p) {
5660 			RETURN_COPY_DEREF(member_p);
5661 		}
5662 	} else {
5663 		zval rv;
5664 
5665 		if (!object) {
5666 			zend_argument_type_error(1, "must be provided for instance properties");
5667 			RETURN_THROWS();
5668 		}
5669 
5670 		/* TODO: Should this always use intern->ce? */
5671 		if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5672 			_DO_THROW("Given object is not an instance of the class this property was declared in");
5673 			RETURN_THROWS();
5674 		}
5675 
5676 		member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv);
5677 		if (member_p != &rv) {
5678 			RETURN_COPY_DEREF(member_p);
5679 		} else {
5680 			if (Z_ISREF_P(member_p)) {
5681 				zend_unwrap_reference(member_p);
5682 			}
5683 			RETURN_COPY_VALUE(member_p);
5684 		}
5685 	}
5686 }
5687 /* }}} */
5688 
5689 /* {{{ Sets this property's value */
ZEND_METHOD(ReflectionProperty,setValue)5690 ZEND_METHOD(ReflectionProperty, setValue)
5691 {
5692 	reflection_object *intern;
5693 	property_reference *ref;
5694 	zval *object;
5695 	zval *value;
5696 	zval *tmp;
5697 
5698 	GET_REFLECTION_OBJECT_PTR(ref);
5699 
5700 	if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5701 		if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
5702 			if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &tmp, &value) == FAILURE) {
5703 				RETURN_THROWS();
5704 			}
5705 		}
5706 
5707 		zend_update_static_property_ex(intern->ce, ref->unmangled_name, value);
5708 	} else {
5709 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) {
5710 			RETURN_THROWS();
5711 		}
5712 
5713 		zend_update_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, value);
5714 	}
5715 }
5716 /* }}} */
5717 
5718 /* {{{ Returns this property's value */
ZEND_METHOD(ReflectionProperty,isInitialized)5719 ZEND_METHOD(ReflectionProperty, isInitialized)
5720 {
5721 	reflection_object *intern;
5722 	property_reference *ref;
5723 	zval *object = NULL;
5724 	zval *member_p = NULL;
5725 
5726 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) {
5727 		RETURN_THROWS();
5728 	}
5729 
5730 	GET_REFLECTION_OBJECT_PTR(ref);
5731 
5732 	if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5733 		member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 1);
5734 		if (member_p) {
5735 			RETURN_BOOL(!Z_ISUNDEF_P(member_p));
5736 		}
5737 		RETURN_FALSE;
5738 	} else {
5739 		zend_class_entry *old_scope;
5740 		int retval;
5741 
5742 		if (!object) {
5743 			zend_argument_type_error(1, "must be provided for instance properties");
5744 			RETURN_THROWS();
5745 		}
5746 
5747 		/* TODO: Should this always use intern->ce? */
5748 		if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5749 			_DO_THROW("Given object is not an instance of the class this property was declared in");
5750 			RETURN_THROWS();
5751 		}
5752 
5753 		old_scope = EG(fake_scope);
5754 		EG(fake_scope) = intern->ce;
5755 		retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object), ref->unmangled_name, ZEND_PROPERTY_EXISTS, NULL);
5756 		EG(fake_scope) = old_scope;
5757 
5758 		RETVAL_BOOL(retval);
5759 	}
5760 }
5761 /* }}} */
5762 
5763 /* {{{ Get the declaring class */
ZEND_METHOD(ReflectionProperty,getDeclaringClass)5764 ZEND_METHOD(ReflectionProperty, getDeclaringClass)
5765 {
5766 	reflection_object *intern;
5767 	property_reference *ref;
5768 	zend_class_entry *ce;
5769 
5770 	if (zend_parse_parameters_none() == FAILURE) {
5771 		RETURN_THROWS();
5772 	}
5773 	GET_REFLECTION_OBJECT_PTR(ref);
5774 
5775 	ce = ref->prop ? ref->prop->ce : intern->ce;
5776 	zend_reflection_class_factory(ce, return_value);
5777 }
5778 /* }}} */
5779 
5780 /* {{{ Returns the doc comment for this property */
ZEND_METHOD(ReflectionProperty,getDocComment)5781 ZEND_METHOD(ReflectionProperty, getDocComment)
5782 {
5783 	reflection_object *intern;
5784 	property_reference *ref;
5785 
5786 	if (zend_parse_parameters_none() == FAILURE) {
5787 		RETURN_THROWS();
5788 	}
5789 	GET_REFLECTION_OBJECT_PTR(ref);
5790 	if (ref->prop && ref->prop->doc_comment) {
5791 		RETURN_STR_COPY(ref->prop->doc_comment);
5792 	}
5793 	RETURN_FALSE;
5794 }
5795 /* }}} */
5796 
5797 /* {{{ Returns the attributes of this property */
ZEND_METHOD(ReflectionProperty,getAttributes)5798 ZEND_METHOD(ReflectionProperty, getAttributes)
5799 {
5800 	reflection_object *intern;
5801 	property_reference *ref;
5802 
5803 	GET_REFLECTION_OBJECT_PTR(ref);
5804 
5805 	if (ref->prop == NULL) {
5806 		RETURN_EMPTY_ARRAY();
5807 	}
5808 
5809 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
5810 		ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY,
5811 		ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL);
5812 }
5813 /* }}} */
5814 
5815 /* {{{ Sets whether non-public properties can be requested */
ZEND_METHOD(ReflectionProperty,setAccessible)5816 ZEND_METHOD(ReflectionProperty, setAccessible)
5817 {
5818 	bool visible;
5819 
5820 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
5821 		RETURN_THROWS();
5822 	}
5823 }
5824 /* }}} */
5825 
5826 /* {{{ Returns the type associated with the property */
ZEND_METHOD(ReflectionProperty,getType)5827 ZEND_METHOD(ReflectionProperty, getType)
5828 {
5829 	reflection_object *intern;
5830 	property_reference *ref;
5831 
5832 	if (zend_parse_parameters_none() == FAILURE) {
5833 		RETURN_THROWS();
5834 	}
5835 
5836 	GET_REFLECTION_OBJECT_PTR(ref);
5837 
5838 	if (!ref->prop || !ZEND_TYPE_IS_SET(ref->prop->type)) {
5839 		RETURN_NULL();
5840 	}
5841 
5842 	reflection_type_factory(ref->prop->type, return_value, 1);
5843 }
5844 /* }}} */
5845 
5846 /* {{{ Returns whether property has a type */
ZEND_METHOD(ReflectionProperty,hasType)5847 ZEND_METHOD(ReflectionProperty, hasType)
5848 {
5849 	reflection_object *intern;
5850 	property_reference *ref;
5851 
5852 	if (zend_parse_parameters_none() == FAILURE) {
5853 		RETURN_THROWS();
5854 	}
5855 
5856 	GET_REFLECTION_OBJECT_PTR(ref);
5857 
5858 	RETVAL_BOOL(ref->prop && ZEND_TYPE_IS_SET(ref->prop->type));
5859 }
5860 /* }}} */
5861 
5862 /* {{{ Returns whether property has a default value */
ZEND_METHOD(ReflectionProperty,hasDefaultValue)5863 ZEND_METHOD(ReflectionProperty, hasDefaultValue)
5864 {
5865 	reflection_object *intern;
5866 	property_reference *ref;
5867 	zend_property_info *prop_info;
5868 	zval *prop;
5869 
5870 	if (zend_parse_parameters_none() == FAILURE) {
5871 		RETURN_THROWS();
5872 	}
5873 
5874 	GET_REFLECTION_OBJECT_PTR(ref);
5875 
5876 	prop_info = ref->prop;
5877 
5878 	if (prop_info == NULL) {
5879 		RETURN_FALSE;
5880 	}
5881 
5882 	prop = property_get_default(prop_info);
5883 	RETURN_BOOL(!Z_ISUNDEF_P(prop));
5884 }
5885 /* }}} */
5886 
5887 /* {{{ Returns the default value of a property */
ZEND_METHOD(ReflectionProperty,getDefaultValue)5888 ZEND_METHOD(ReflectionProperty, getDefaultValue)
5889 {
5890 	reflection_object *intern;
5891 	property_reference *ref;
5892 	zend_property_info *prop_info;
5893 	zval *prop;
5894 
5895 	if (zend_parse_parameters_none() == FAILURE) {
5896 		RETURN_THROWS();
5897 	}
5898 
5899 	GET_REFLECTION_OBJECT_PTR(ref);
5900 
5901 	prop_info = ref->prop;
5902 
5903 	if (prop_info == NULL) {
5904 		return; // throw exception?
5905 	}
5906 
5907 	prop = property_get_default(prop_info);
5908 	if (Z_ISUNDEF_P(prop)) {
5909 		return;
5910 	}
5911 
5912 	/* copy: enforce read only access */
5913 	ZVAL_DEREF(prop);
5914 	ZVAL_COPY_OR_DUP(return_value, prop);
5915 
5916 	/* this is necessary to make it able to work with default array
5917 	* properties, returned to user */
5918 	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
5919 		if (UNEXPECTED(zval_update_constant_ex(return_value, prop_info->ce) != SUCCESS)) {
5920 			RETURN_THROWS();
5921 		}
5922 	}
5923 }
5924 /* }}} */
5925 
5926 /* {{{ Constructor. Throws an Exception in case the given extension does not exist */
ZEND_METHOD(ReflectionExtension,__construct)5927 ZEND_METHOD(ReflectionExtension, __construct)
5928 {
5929 	zval *object;
5930 	char *lcname;
5931 	reflection_object *intern;
5932 	zend_module_entry *module;
5933 	char *name_str;
5934 	size_t name_len;
5935 	ALLOCA_FLAG(use_heap)
5936 
5937 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
5938 		RETURN_THROWS();
5939 	}
5940 
5941 	object = ZEND_THIS;
5942 	intern = Z_REFLECTION_P(object);
5943 	lcname = do_alloca(name_len + 1, use_heap);
5944 	zend_str_tolower_copy(lcname, name_str, name_len);
5945 	if ((module = zend_hash_str_find_ptr(&module_registry, lcname, name_len)) == NULL) {
5946 		free_alloca(lcname, use_heap);
5947 		zend_throw_exception_ex(reflection_exception_ptr, 0,
5948 			"Extension \"%s\" does not exist", name_str);
5949 		RETURN_THROWS();
5950 	}
5951 	free_alloca(lcname, use_heap);
5952 	ZVAL_STRING(reflection_prop_name(object), module->name);
5953 	intern->ptr = module;
5954 	intern->ref_type = REF_TYPE_OTHER;
5955 	intern->ce = NULL;
5956 }
5957 /* }}} */
5958 
5959 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionExtension,__toString)5960 ZEND_METHOD(ReflectionExtension, __toString)
5961 {
5962 	reflection_object *intern;
5963 	zend_module_entry *module;
5964 	smart_str str = {0};
5965 
5966 	if (zend_parse_parameters_none() == FAILURE) {
5967 		RETURN_THROWS();
5968 	}
5969 	GET_REFLECTION_OBJECT_PTR(module);
5970 	_extension_string(&str, module, "");
5971 	RETURN_STR(smart_str_extract(&str));
5972 }
5973 /* }}} */
5974 
5975 /* {{{ Returns this extension's name */
ZEND_METHOD(ReflectionExtension,getName)5976 ZEND_METHOD(ReflectionExtension, getName)
5977 {
5978 	reflection_object *intern;
5979 	zend_module_entry *module;
5980 
5981 	if (zend_parse_parameters_none() == FAILURE) {
5982 		RETURN_THROWS();
5983 	}
5984 
5985 	GET_REFLECTION_OBJECT_PTR(module);
5986 	RETURN_STRING(module->name);
5987 }
5988 /* }}} */
5989 
5990 /* {{{ Returns this extension's version */
ZEND_METHOD(ReflectionExtension,getVersion)5991 ZEND_METHOD(ReflectionExtension, getVersion)
5992 {
5993 	reflection_object *intern;
5994 	zend_module_entry *module;
5995 
5996 	if (zend_parse_parameters_none() == FAILURE) {
5997 		RETURN_THROWS();
5998 	}
5999 	GET_REFLECTION_OBJECT_PTR(module);
6000 
6001 	/* An extension does not necessarily have a version number */
6002 	if (module->version == NO_VERSION_YET) {
6003 		RETURN_NULL();
6004 	} else {
6005 		RETURN_STRING(module->version);
6006 	}
6007 }
6008 /* }}} */
6009 
6010 /* {{{ Returns an array of this extension's functions */
ZEND_METHOD(ReflectionExtension,getFunctions)6011 ZEND_METHOD(ReflectionExtension, getFunctions)
6012 {
6013 	reflection_object *intern;
6014 	zend_module_entry *module;
6015 	zval function;
6016 	zend_function *fptr;
6017 
6018 	if (zend_parse_parameters_none() == FAILURE) {
6019 		RETURN_THROWS();
6020 	}
6021 	GET_REFLECTION_OBJECT_PTR(module);
6022 
6023 	array_init(return_value);
6024 	ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), fptr) {
6025 		if (fptr->common.type==ZEND_INTERNAL_FUNCTION
6026 			&& fptr->internal_function.module == module) {
6027 			reflection_function_factory(fptr, NULL, &function);
6028 			zend_hash_update(Z_ARRVAL_P(return_value), fptr->common.function_name, &function);
6029 		}
6030 	} ZEND_HASH_FOREACH_END();
6031 }
6032 /* }}} */
6033 
6034 /* {{{ Returns an associative array containing this extension's constants and their values */
ZEND_METHOD(ReflectionExtension,getConstants)6035 ZEND_METHOD(ReflectionExtension, getConstants)
6036 {
6037 	reflection_object *intern;
6038 	zend_module_entry *module;
6039 	zend_constant *constant;
6040 
6041 	if (zend_parse_parameters_none() == FAILURE) {
6042 		RETURN_THROWS();
6043 	}
6044 	GET_REFLECTION_OBJECT_PTR(module);
6045 
6046 	array_init(return_value);
6047 	ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
6048 		if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) {
6049 			zval const_val;
6050 			ZVAL_COPY_OR_DUP(&const_val, &constant->value);
6051 			zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val);
6052 		}
6053 	} ZEND_HASH_FOREACH_END();
6054 }
6055 /* }}} */
6056 
6057 /* {{{ _addinientry */
_addinientry(zend_ini_entry * ini_entry,zval * retval,int number)6058 static void _addinientry(zend_ini_entry *ini_entry, zval *retval, int number)
6059 {
6060 	if (number == ini_entry->module_number) {
6061 		zval zv;
6062 		if (ini_entry->value) {
6063 			ZVAL_STR_COPY(&zv, ini_entry->value);
6064 		} else {
6065 			ZVAL_NULL(&zv);
6066 		}
6067 		zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &zv);
6068 	}
6069 }
6070 /* }}} */
6071 
6072 /* {{{ Returns an associative array containing this extension's INI entries and their values */
ZEND_METHOD(ReflectionExtension,getINIEntries)6073 ZEND_METHOD(ReflectionExtension, getINIEntries)
6074 {
6075 	reflection_object *intern;
6076 	zend_module_entry *module;
6077 	zend_ini_entry *ini_entry;
6078 
6079 	if (zend_parse_parameters_none() == FAILURE) {
6080 		RETURN_THROWS();
6081 	}
6082 	GET_REFLECTION_OBJECT_PTR(module);
6083 
6084 	array_init(return_value);
6085 	ZEND_HASH_MAP_FOREACH_PTR(EG(ini_directives), ini_entry) {
6086 		_addinientry(ini_entry, return_value, module->module_number);
6087 	} ZEND_HASH_FOREACH_END();
6088 }
6089 /* }}} */
6090 
6091 /* {{{ add_extension_class */
add_extension_class(zend_class_entry * ce,zend_string * key,zval * class_array,zend_module_entry * module,bool add_reflection_class)6092 static void add_extension_class(zend_class_entry *ce, zend_string *key, zval *class_array, zend_module_entry *module, bool add_reflection_class)
6093 {
6094 	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
6095 		zend_string *name;
6096 
6097 		if (!zend_string_equals_ci(ce->name, key)) {
6098 			/* This is a class alias, use alias name */
6099 			name = key;
6100 		} else {
6101 			/* Use class name */
6102 			name = ce->name;
6103 		}
6104 		if (add_reflection_class) {
6105 			zval zclass;
6106 			zend_reflection_class_factory(ce, &zclass);
6107 			zend_hash_update(Z_ARRVAL_P(class_array), name, &zclass);
6108 		} else {
6109 			add_next_index_str(class_array, zend_string_copy(name));
6110 		}
6111 	}
6112 }
6113 /* }}} */
6114 
6115 /* {{{ Returns an array containing ReflectionClass objects for all classes of this extension */
ZEND_METHOD(ReflectionExtension,getClasses)6116 ZEND_METHOD(ReflectionExtension, getClasses)
6117 {
6118 	reflection_object *intern;
6119 	zend_module_entry *module;
6120 	zend_string *key;
6121 	zend_class_entry *ce;
6122 
6123 	if (zend_parse_parameters_none() == FAILURE) {
6124 		RETURN_THROWS();
6125 	}
6126 	GET_REFLECTION_OBJECT_PTR(module);
6127 
6128 	array_init(return_value);
6129 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
6130 		add_extension_class(ce, key, return_value, module, 1);
6131 	} ZEND_HASH_FOREACH_END();
6132 }
6133 /* }}} */
6134 
6135 /* {{{ Returns an array containing all names of all classes of this extension */
ZEND_METHOD(ReflectionExtension,getClassNames)6136 ZEND_METHOD(ReflectionExtension, getClassNames)
6137 {
6138 	reflection_object *intern;
6139 	zend_module_entry *module;
6140 	zend_string *key;
6141 	zend_class_entry *ce;
6142 
6143 	if (zend_parse_parameters_none() == FAILURE) {
6144 		RETURN_THROWS();
6145 	}
6146 	GET_REFLECTION_OBJECT_PTR(module);
6147 
6148 	array_init(return_value);
6149 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
6150 		add_extension_class(ce, key, return_value, module, 0);
6151 	} ZEND_HASH_FOREACH_END();
6152 }
6153 /* }}} */
6154 
6155 /* {{{ Returns an array containing all names of all extensions this extension depends on */
ZEND_METHOD(ReflectionExtension,getDependencies)6156 ZEND_METHOD(ReflectionExtension, getDependencies)
6157 {
6158 	reflection_object *intern;
6159 	zend_module_entry *module;
6160 	const zend_module_dep *dep;
6161 
6162 	if (zend_parse_parameters_none() == FAILURE) {
6163 		RETURN_THROWS();
6164 	}
6165 	GET_REFLECTION_OBJECT_PTR(module);
6166 
6167 	dep = module->deps;
6168 
6169 	if (!dep)
6170 	{
6171 		RETURN_EMPTY_ARRAY();
6172 	}
6173 
6174 	array_init(return_value);
6175 	while(dep->name) {
6176 		zend_string *relation;
6177 		char *rel_type;
6178 		size_t len = 0;
6179 
6180 		switch(dep->type) {
6181 			case MODULE_DEP_REQUIRED:
6182 				rel_type = "Required";
6183 				len += sizeof("Required") - 1;
6184 				break;
6185 			case MODULE_DEP_CONFLICTS:
6186 				rel_type = "Conflicts";
6187 				len += sizeof("Conflicts") - 1;
6188 				break;
6189 			case MODULE_DEP_OPTIONAL:
6190 				rel_type = "Optional";
6191 				len += sizeof("Optional") - 1;
6192 				break;
6193 			default:
6194 				rel_type = "Error"; /* shouldn't happen */
6195 				len += sizeof("Error") - 1;
6196 				break;
6197 		}
6198 
6199 		if (dep->rel) {
6200 			len += strlen(dep->rel) + 1;
6201 		}
6202 
6203 		if (dep->version) {
6204 			len += strlen(dep->version) + 1;
6205 		}
6206 
6207 		relation = zend_string_alloc(len, 0);
6208 		snprintf(ZSTR_VAL(relation), ZSTR_LEN(relation) + 1, "%s%s%s%s%s",
6209 						rel_type,
6210 						dep->rel ? " " : "",
6211 						dep->rel ? dep->rel : "",
6212 						dep->version ? " " : "",
6213 						dep->version ? dep->version : "");
6214 		add_assoc_str(return_value, dep->name, relation);
6215 		dep++;
6216 	}
6217 }
6218 /* }}} */
6219 
6220 /* {{{ Prints phpinfo block for the extension */
ZEND_METHOD(ReflectionExtension,info)6221 ZEND_METHOD(ReflectionExtension, info)
6222 {
6223 	reflection_object *intern;
6224 	zend_module_entry *module;
6225 
6226 	if (zend_parse_parameters_none() == FAILURE) {
6227 		RETURN_THROWS();
6228 	}
6229 	GET_REFLECTION_OBJECT_PTR(module);
6230 
6231 	php_info_print_module(module);
6232 }
6233 /* }}} */
6234 
6235 /* {{{ Returns whether this extension is persistent */
ZEND_METHOD(ReflectionExtension,isPersistent)6236 ZEND_METHOD(ReflectionExtension, isPersistent)
6237 {
6238 	reflection_object *intern;
6239 	zend_module_entry *module;
6240 
6241 	if (zend_parse_parameters_none() == FAILURE) {
6242 		RETURN_THROWS();
6243 	}
6244 	GET_REFLECTION_OBJECT_PTR(module);
6245 
6246 	RETURN_BOOL(module->type == MODULE_PERSISTENT);
6247 }
6248 /* }}} */
6249 
6250 /* {{{ Returns whether this extension is temporary */
ZEND_METHOD(ReflectionExtension,isTemporary)6251 ZEND_METHOD(ReflectionExtension, isTemporary)
6252 {
6253 	reflection_object *intern;
6254 	zend_module_entry *module;
6255 
6256 	if (zend_parse_parameters_none() == FAILURE) {
6257 		RETURN_THROWS();
6258 	}
6259 	GET_REFLECTION_OBJECT_PTR(module);
6260 
6261 	RETURN_BOOL(module->type == MODULE_TEMPORARY);
6262 }
6263 /* }}} */
6264 
6265 /* {{{ Constructor. Throws an Exception in case the given Zend extension does not exist */
ZEND_METHOD(ReflectionZendExtension,__construct)6266 ZEND_METHOD(ReflectionZendExtension, __construct)
6267 {
6268 	zval *object;
6269 	reflection_object *intern;
6270 	zend_extension *extension;
6271 	char *name_str;
6272 	size_t name_len;
6273 
6274 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
6275 		RETURN_THROWS();
6276 	}
6277 
6278 	object = ZEND_THIS;
6279 	intern = Z_REFLECTION_P(object);
6280 
6281 	extension = zend_get_extension(name_str);
6282 	if (!extension) {
6283 		zend_throw_exception_ex(reflection_exception_ptr, 0,
6284 				"Zend Extension \"%s\" does not exist", name_str);
6285 		RETURN_THROWS();
6286 	}
6287 	ZVAL_STRING(reflection_prop_name(object), extension->name);
6288 	intern->ptr = extension;
6289 	intern->ref_type = REF_TYPE_OTHER;
6290 	intern->ce = NULL;
6291 }
6292 /* }}} */
6293 
6294 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionZendExtension,__toString)6295 ZEND_METHOD(ReflectionZendExtension, __toString)
6296 {
6297 	reflection_object *intern;
6298 	zend_extension *extension;
6299 	smart_str str = {0};
6300 
6301 	if (zend_parse_parameters_none() == FAILURE) {
6302 		RETURN_THROWS();
6303 	}
6304 	GET_REFLECTION_OBJECT_PTR(extension);
6305 	_zend_extension_string(&str, extension, "");
6306 	RETURN_STR(smart_str_extract(&str));
6307 }
6308 /* }}} */
6309 
6310 /* {{{ Returns the name of this Zend extension */
ZEND_METHOD(ReflectionZendExtension,getName)6311 ZEND_METHOD(ReflectionZendExtension, getName)
6312 {
6313 	reflection_object *intern;
6314 	zend_extension *extension;
6315 
6316 	if (zend_parse_parameters_none() == FAILURE) {
6317 		RETURN_THROWS();
6318 	}
6319 	GET_REFLECTION_OBJECT_PTR(extension);
6320 
6321 	RETURN_STRING(extension->name);
6322 }
6323 /* }}} */
6324 
6325 /* {{{ Returns the version information of this Zend extension */
ZEND_METHOD(ReflectionZendExtension,getVersion)6326 ZEND_METHOD(ReflectionZendExtension, getVersion)
6327 {
6328 	reflection_object *intern;
6329 	zend_extension *extension;
6330 
6331 	if (zend_parse_parameters_none() == FAILURE) {
6332 		RETURN_THROWS();
6333 	}
6334 	GET_REFLECTION_OBJECT_PTR(extension);
6335 
6336 	if (extension->version) {
6337 		RETURN_STRING(extension->version);
6338 	} else {
6339 		RETURN_EMPTY_STRING();
6340 	}
6341 }
6342 /* }}} */
6343 
6344 /* {{{ Returns the name of this Zend extension's author */
ZEND_METHOD(ReflectionZendExtension,getAuthor)6345 ZEND_METHOD(ReflectionZendExtension, getAuthor)
6346 {
6347 	reflection_object *intern;
6348 	zend_extension *extension;
6349 
6350 	if (zend_parse_parameters_none() == FAILURE) {
6351 		RETURN_THROWS();
6352 	}
6353 	GET_REFLECTION_OBJECT_PTR(extension);
6354 
6355 	if (extension->author) {
6356 		RETURN_STRING(extension->author);
6357 	} else {
6358 		RETURN_EMPTY_STRING();
6359 	}
6360 }
6361 /* }}} */
6362 
6363 /* {{{ Returns this Zend extension's URL*/
ZEND_METHOD(ReflectionZendExtension,getURL)6364 ZEND_METHOD(ReflectionZendExtension, getURL)
6365 {
6366 	reflection_object *intern;
6367 	zend_extension *extension;
6368 
6369 	if (zend_parse_parameters_none() == FAILURE) {
6370 		RETURN_THROWS();
6371 	}
6372 	GET_REFLECTION_OBJECT_PTR(extension);
6373 
6374 	if (extension->URL) {
6375 		RETURN_STRING(extension->URL);
6376 	} else {
6377 		RETURN_EMPTY_STRING();
6378 	}
6379 }
6380 /* }}} */
6381 
6382 /* {{{ Returns this Zend extension's copyright information */
ZEND_METHOD(ReflectionZendExtension,getCopyright)6383 ZEND_METHOD(ReflectionZendExtension, getCopyright)
6384 {
6385 	reflection_object *intern;
6386 	zend_extension *extension;
6387 
6388 	if (zend_parse_parameters_none() == FAILURE) {
6389 		RETURN_THROWS();
6390 	}
6391 	GET_REFLECTION_OBJECT_PTR(extension);
6392 
6393 	if (extension->copyright) {
6394 		RETURN_STRING(extension->copyright);
6395 	} else {
6396 		RETURN_EMPTY_STRING();
6397 	}
6398 }
6399 /* }}} */
6400 
6401 /* {{{     Dummy constructor -- always throws ReflectionExceptions. */
ZEND_METHOD(ReflectionReference,__construct)6402 ZEND_METHOD(ReflectionReference, __construct)
6403 {
6404 	_DO_THROW(
6405 		"Cannot directly instantiate ReflectionReference. "
6406 		"Use ReflectionReference::fromArrayElement() instead"
6407 	);
6408 }
6409 /* }}} */
6410 
is_ignorable_reference(HashTable * ht,zval * ref)6411 static bool is_ignorable_reference(HashTable *ht, zval *ref) {
6412 	if (Z_REFCOUNT_P(ref) != 1) {
6413 		return 0;
6414 	}
6415 
6416 	/* Directly self-referential arrays are treated as proper references
6417 	 * in zend_array_dup() despite rc=1. */
6418 	return Z_TYPE_P(Z_REFVAL_P(ref)) != IS_ARRAY || Z_ARRVAL_P(Z_REFVAL_P(ref)) != ht;
6419 }
6420 
6421 /* {{{     Create ReflectionReference for array item. Returns null if not a reference. */
ZEND_METHOD(ReflectionReference,fromArrayElement)6422 ZEND_METHOD(ReflectionReference, fromArrayElement)
6423 {
6424 	HashTable *ht;
6425 	zval *item;
6426 	zend_string *string_key = NULL;
6427 	zend_long int_key = 0;
6428 	reflection_object *intern;
6429 
6430 	ZEND_PARSE_PARAMETERS_START(2, 2)
6431 		Z_PARAM_ARRAY_HT(ht)
6432 		Z_PARAM_STR_OR_LONG(string_key, int_key)
6433 	ZEND_PARSE_PARAMETERS_END();
6434 
6435 	if (string_key) {
6436 		item = zend_hash_find(ht, string_key);
6437 	} else {
6438 		item = zend_hash_index_find(ht, int_key);
6439 	}
6440 
6441 	if (!item) {
6442 		_DO_THROW("Array key not found");
6443 		RETURN_THROWS();
6444 	}
6445 
6446 	if (Z_TYPE_P(item) != IS_REFERENCE || is_ignorable_reference(ht, item)) {
6447 		RETURN_NULL();
6448 	}
6449 
6450 	object_init_ex(return_value, reflection_reference_ptr);
6451 	intern = Z_REFLECTION_P(return_value);
6452 	ZVAL_COPY(&intern->obj, item);
6453 	intern->ref_type = REF_TYPE_OTHER;
6454 }
6455 /* }}} */
6456 
6457 /* {{{     Returns a unique identifier for the reference.
6458  *     The format of the return value is unspecified and may change. */
ZEND_METHOD(ReflectionReference,getId)6459 ZEND_METHOD(ReflectionReference, getId)
6460 {
6461 	reflection_object *intern;
6462 	unsigned char digest[20];
6463 	PHP_SHA1_CTX context;
6464 
6465 	if (zend_parse_parameters_none() == FAILURE) {
6466 		RETURN_THROWS();
6467 	}
6468 
6469 	intern = Z_REFLECTION_P(getThis());
6470 	if (Z_TYPE(intern->obj) != IS_REFERENCE) {
6471 		_DO_THROW("Corrupted ReflectionReference object");
6472 		RETURN_THROWS();
6473 	}
6474 
6475 	if (!REFLECTION_G(key_initialized)) {
6476 		if (php_random_bytes_throw(&REFLECTION_G(key), 16) == FAILURE) {
6477 			RETURN_THROWS();
6478 		}
6479 
6480 		REFLECTION_G(key_initialized) = 1;
6481 	}
6482 
6483 	/* SHA1(ref || key) to avoid directly exposing memory addresses. */
6484 	PHP_SHA1Init(&context);
6485 	PHP_SHA1Update(&context, (unsigned char *) &Z_REF(intern->obj), sizeof(zend_reference *));
6486 	PHP_SHA1Update(&context, REFLECTION_G(key), REFLECTION_KEY_LEN);
6487 	PHP_SHA1Final(digest, &context);
6488 
6489 	RETURN_STRINGL((char *) digest, sizeof(digest));
6490 }
6491 /* }}} */
6492 
ZEND_METHOD(ReflectionAttribute,__construct)6493 ZEND_METHOD(ReflectionAttribute, __construct)
6494 {
6495 	_DO_THROW("Cannot directly instantiate ReflectionAttribute");
6496 }
6497 
ZEND_METHOD(ReflectionAttribute,__clone)6498 ZEND_METHOD(ReflectionAttribute, __clone)
6499 {
6500 	/* Should never be executable */
6501 	_DO_THROW("Cannot clone object using __clone()");
6502 }
6503 
6504 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionAttribute,__toString)6505 ZEND_METHOD(ReflectionAttribute, __toString)
6506 {
6507 	reflection_object *intern;
6508 	attribute_reference *attr;
6509 
6510 	if (zend_parse_parameters_none() == FAILURE) {
6511 		RETURN_THROWS();
6512 	}
6513 
6514 	GET_REFLECTION_OBJECT_PTR(attr);
6515 
6516 	smart_str str = {0};
6517 	smart_str_appends(&str, "Attribute [ ");
6518 	smart_str_append(&str, attr->data->name);
6519 	smart_str_appends(&str, " ]");
6520 
6521 	if (attr->data->argc > 0) {
6522 		smart_str_appends(&str, " {\n");
6523 		smart_str_append_printf(&str, "  - Arguments [%d] {\n", attr->data->argc);
6524 
6525 		for (uint32_t i = 0; i < attr->data->argc; i++) {
6526 			smart_str_append_printf(&str, "    Argument #%d [ ", i);
6527 			if (attr->data->args[i].name != NULL) {
6528 				smart_str_append(&str, attr->data->args[i].name);
6529 				smart_str_appends(&str, " = ");
6530 			}
6531 
6532 			if (format_default_value(&str, &attr->data->args[i].value) == FAILURE) {
6533 				smart_str_free(&str);
6534 				RETURN_THROWS();
6535 			}
6536 
6537 			smart_str_appends(&str, " ]\n");
6538 		}
6539 		smart_str_appends(&str, "  }\n");
6540 
6541 		smart_str_appends(&str, "}\n");
6542 	} else {
6543 		smart_str_appendc(&str, '\n');
6544 	}
6545 
6546 	RETURN_STR(smart_str_extract(&str));
6547 }
6548 /* }}} */
6549 
6550 /* {{{ *	   Returns the name of the attribute */
ZEND_METHOD(ReflectionAttribute,getName)6551 ZEND_METHOD(ReflectionAttribute, getName)
6552 {
6553 	reflection_object *intern;
6554 	attribute_reference *attr;
6555 
6556 	if (zend_parse_parameters_none() == FAILURE) {
6557 		RETURN_THROWS();
6558 	}
6559 	GET_REFLECTION_OBJECT_PTR(attr);
6560 
6561 	RETURN_STR_COPY(attr->data->name);
6562 }
6563 /* }}} */
6564 
6565 /* {{{ *	   Returns the target of the attribute */
ZEND_METHOD(ReflectionAttribute,getTarget)6566 ZEND_METHOD(ReflectionAttribute, getTarget)
6567 {
6568 	reflection_object *intern;
6569 	attribute_reference *attr;
6570 
6571 	if (zend_parse_parameters_none() == FAILURE) {
6572 		RETURN_THROWS();
6573 	}
6574 	GET_REFLECTION_OBJECT_PTR(attr);
6575 
6576 	RETURN_LONG(attr->target);
6577 }
6578 /* }}} */
6579 
6580 /* {{{ *	   Returns true if the attribute is repeated */
ZEND_METHOD(ReflectionAttribute,isRepeated)6581 ZEND_METHOD(ReflectionAttribute, isRepeated)
6582 {
6583 	reflection_object *intern;
6584 	attribute_reference *attr;
6585 
6586 	if (zend_parse_parameters_none() == FAILURE) {
6587 		RETURN_THROWS();
6588 	}
6589 	GET_REFLECTION_OBJECT_PTR(attr);
6590 
6591 	RETURN_BOOL(zend_is_attribute_repeated(attr->attributes, attr->data));
6592 }
6593 /* }}} */
6594 
6595 /* {{{ *	   Returns the arguments passed to the attribute */
ZEND_METHOD(ReflectionAttribute,getArguments)6596 ZEND_METHOD(ReflectionAttribute, getArguments)
6597 {
6598 	reflection_object *intern;
6599 	attribute_reference *attr;
6600 
6601 	zval tmp;
6602 	uint32_t i;
6603 
6604 	if (zend_parse_parameters_none() == FAILURE) {
6605 		RETURN_THROWS();
6606 	}
6607 	GET_REFLECTION_OBJECT_PTR(attr);
6608 
6609 	array_init(return_value);
6610 
6611 	for (i = 0; i < attr->data->argc; i++) {
6612 		if (FAILURE == zend_get_attribute_value(&tmp, attr->data, i, attr->scope)) {
6613 			RETURN_THROWS();
6614 		}
6615 
6616 		if (attr->data->args[i].name) {
6617 			/* We ensured at compile-time that there are no duplicate parameter names. */
6618 			zend_hash_add_new(Z_ARRVAL_P(return_value), attr->data->args[i].name, &tmp);
6619 		} else {
6620 			add_next_index_zval(return_value, &tmp);
6621 		}
6622 	}
6623 }
6624 /* }}} */
6625 
call_attribute_constructor(zend_attribute * attr,zend_class_entry * ce,zend_object * obj,zval * args,uint32_t argc,HashTable * named_params,zend_string * filename)6626 static int call_attribute_constructor(
6627 	zend_attribute *attr, zend_class_entry *ce, zend_object *obj,
6628 	zval *args, uint32_t argc, HashTable *named_params, zend_string *filename)
6629 {
6630 	zend_function *ctor = ce->constructor;
6631 	zend_execute_data *call = NULL;
6632 	ZEND_ASSERT(ctor != NULL);
6633 
6634 	if (!(ctor->common.fn_flags & ZEND_ACC_PUBLIC)) {
6635 		zend_throw_error(NULL, "Attribute constructor of class %s must be public", ZSTR_VAL(ce->name));
6636 		return FAILURE;
6637 	}
6638 
6639 	if (filename) {
6640 		/* Set up dummy call frame that makes it look like the attribute was invoked
6641 		 * from where it occurs in the code. */
6642 		zend_function dummy_func;
6643 		zend_op *opline;
6644 
6645 		memset(&dummy_func, 0, sizeof(zend_function));
6646 
6647 		call = zend_vm_stack_push_call_frame_ex(
6648 			ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_execute_data), sizeof(zval)) +
6649 			ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_op), sizeof(zval)) +
6650 			ZEND_MM_ALIGNED_SIZE_EX(sizeof(zend_function), sizeof(zval)),
6651 			0, &dummy_func, 0, NULL);
6652 
6653 		opline = (zend_op*)(call + 1);
6654 		memset(opline, 0, sizeof(zend_op));
6655 		opline->opcode = ZEND_DO_FCALL;
6656 		opline->lineno = attr->lineno;
6657 
6658 		call->opline = opline;
6659 		call->call = NULL;
6660 		call->return_value = NULL;
6661 		call->func = (zend_function*)(call->opline + 1);
6662 		call->prev_execute_data = EG(current_execute_data);
6663 
6664 		memset(call->func, 0, sizeof(zend_function));
6665 		call->func->type = ZEND_USER_FUNCTION;
6666 		call->func->op_array.fn_flags =
6667 			attr->flags & ZEND_ATTRIBUTE_STRICT_TYPES ? ZEND_ACC_STRICT_TYPES : 0;
6668 		call->func->op_array.fn_flags |= ZEND_ACC_CALL_VIA_TRAMPOLINE;
6669 		call->func->op_array.filename = filename;
6670 
6671 		EG(current_execute_data) = call;
6672 	}
6673 
6674 	zend_call_known_function(ctor, obj, obj->ce, NULL, argc, args, named_params);
6675 
6676 	if (filename) {
6677 		EG(current_execute_data) = call->prev_execute_data;
6678 		zend_vm_stack_free_call_frame(call);
6679 	}
6680 
6681 	if (EG(exception)) {
6682 		zend_object_store_ctor_failed(obj);
6683 		return FAILURE;
6684 	}
6685 
6686 	return SUCCESS;
6687 }
6688 
attribute_ctor_cleanup(zval * obj,zval * args,uint32_t argc,HashTable * named_params)6689 static void attribute_ctor_cleanup(
6690 		zval *obj, zval *args, uint32_t argc, HashTable *named_params) /* {{{ */
6691 {
6692 	if (obj) {
6693 		zval_ptr_dtor(obj);
6694 	}
6695 
6696 	if (args) {
6697 		uint32_t i;
6698 
6699 		for (i = 0; i < argc; i++) {
6700 			zval_ptr_dtor(&args[i]);
6701 		}
6702 
6703 		efree(args);
6704 	}
6705 
6706 	if (named_params) {
6707 		zend_array_destroy(named_params);
6708 	}
6709 }
6710 /* }}} */
6711 
6712 /* {{{ *	   Returns the attribute as an object */
ZEND_METHOD(ReflectionAttribute,newInstance)6713 ZEND_METHOD(ReflectionAttribute, newInstance)
6714 {
6715 	reflection_object *intern;
6716 	attribute_reference *attr;
6717 	zend_attribute *marker;
6718 
6719 	zend_class_entry *ce;
6720 	zval obj;
6721 
6722 	zval *args = NULL;
6723 	HashTable *named_params = NULL;
6724 
6725 	if (zend_parse_parameters_none() == FAILURE) {
6726 		RETURN_THROWS();
6727 	}
6728 
6729 	GET_REFLECTION_OBJECT_PTR(attr);
6730 
6731 	if (NULL == (ce = zend_lookup_class(attr->data->name))) {
6732 		zend_throw_error(NULL, "Attribute class \"%s\" not found", ZSTR_VAL(attr->data->name));
6733 		RETURN_THROWS();
6734 	}
6735 
6736 	if (NULL == (marker = zend_get_attribute_str(ce->attributes, ZEND_STRL("attribute")))) {
6737 		zend_throw_error(NULL, "Attempting to use non-attribute class \"%s\" as attribute", ZSTR_VAL(attr->data->name));
6738 		RETURN_THROWS();
6739 	}
6740 
6741 	if (ce->type == ZEND_USER_CLASS) {
6742 		uint32_t flags = zend_attribute_attribute_get_flags(marker, ce);
6743 		if (EG(exception)) {
6744 			RETURN_THROWS();
6745 		}
6746 
6747 		if (!(attr->target & flags)) {
6748 			zend_string *location = zend_get_attribute_target_names(attr->target);
6749 			zend_string *allowed = zend_get_attribute_target_names(flags);
6750 
6751 			zend_throw_error(NULL, "Attribute \"%s\" cannot target %s (allowed targets: %s)",
6752 				ZSTR_VAL(attr->data->name), ZSTR_VAL(location), ZSTR_VAL(allowed)
6753 			);
6754 
6755 			zend_string_release(location);
6756 			zend_string_release(allowed);
6757 
6758 			RETURN_THROWS();
6759 		}
6760 
6761 		if (!(flags & ZEND_ATTRIBUTE_IS_REPEATABLE)) {
6762 			if (zend_is_attribute_repeated(attr->attributes, attr->data)) {
6763 				zend_throw_error(NULL, "Attribute \"%s\" must not be repeated", ZSTR_VAL(attr->data->name));
6764 				RETURN_THROWS();
6765 			}
6766 		}
6767 	}
6768 
6769 	if (SUCCESS != object_init_ex(&obj, ce)) {
6770 		RETURN_THROWS();
6771 	}
6772 
6773 	uint32_t argc = 0;
6774 	if (attr->data->argc) {
6775 		args = emalloc(attr->data->argc * sizeof(zval));
6776 
6777 		for (uint32_t i = 0; i < attr->data->argc; i++) {
6778 			zval val;
6779 			if (FAILURE == zend_get_attribute_value(&val, attr->data, i, attr->scope)) {
6780 				attribute_ctor_cleanup(&obj, args, argc, named_params);
6781 				RETURN_THROWS();
6782 			}
6783 			if (attr->data->args[i].name) {
6784 				if (!named_params) {
6785 					named_params = zend_new_array(0);
6786 				}
6787 				zend_hash_add_new(named_params, attr->data->args[i].name, &val);
6788 			} else {
6789 				ZVAL_COPY_VALUE(&args[i], &val);
6790 				argc++;
6791 			}
6792 		}
6793 	}
6794 
6795 	if (ce->constructor) {
6796 		if (FAILURE == call_attribute_constructor(attr->data, ce, Z_OBJ(obj), args, argc, named_params, attr->filename)) {
6797 			attribute_ctor_cleanup(&obj, args, argc, named_params);
6798 			RETURN_THROWS();
6799 		}
6800 	} else if (argc || named_params) {
6801 		attribute_ctor_cleanup(&obj, args, argc, named_params);
6802 		zend_throw_error(NULL, "Attribute class %s does not have a constructor, cannot pass arguments", ZSTR_VAL(ce->name));
6803 		RETURN_THROWS();
6804 	}
6805 
6806 	attribute_ctor_cleanup(NULL, args, argc, named_params);
6807 
6808 	RETURN_COPY_VALUE(&obj);
6809 }
6810 
ZEND_METHOD(ReflectionEnum,__construct)6811 ZEND_METHOD(ReflectionEnum, __construct)
6812 {
6813 	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
6814 	if (EG(exception)) {
6815 		RETURN_THROWS();
6816 	}
6817 
6818 	reflection_object *intern;
6819 	zend_class_entry *ce;
6820 	GET_REFLECTION_OBJECT_PTR(ce);
6821 
6822 	if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
6823 		zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" is not an enum", ZSTR_VAL(ce->name));
6824 		RETURN_THROWS();
6825 	}
6826 }
6827 
ZEND_METHOD(ReflectionEnum,hasCase)6828 ZEND_METHOD(ReflectionEnum, hasCase)
6829 {
6830 	reflection_object *intern;
6831 	zend_class_entry *ce;
6832 	zend_string *name;
6833 
6834 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
6835 		RETURN_THROWS();
6836 	}
6837 
6838 	GET_REFLECTION_OBJECT_PTR(ce);
6839 
6840 	zend_class_constant *class_const = zend_hash_find_ptr(&ce->constants_table, name);
6841 	if (class_const == NULL) {
6842 		RETURN_FALSE;
6843 	}
6844 
6845 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(class_const) & ZEND_CLASS_CONST_IS_CASE);
6846 }
6847 
ZEND_METHOD(ReflectionEnum,getCase)6848 ZEND_METHOD(ReflectionEnum, getCase)
6849 {
6850 	reflection_object *intern;
6851 	zend_class_entry *ce;
6852 	zend_string *name;
6853 
6854 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
6855 		RETURN_THROWS();
6856 	}
6857 
6858 	GET_REFLECTION_OBJECT_PTR(ce);
6859 
6860 	zend_class_constant *constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name);
6861 	if (constant == NULL) {
6862 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Case %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
6863 		RETURN_THROWS();
6864 	}
6865 	if (!(ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE)) {
6866 		zend_throw_exception_ex(reflection_exception_ptr, 0, "%s::%s is not a case", ZSTR_VAL(ce->name), ZSTR_VAL(name));
6867 		RETURN_THROWS();
6868 	}
6869 
6870 	reflection_enum_case_factory(ce, name, constant, return_value);
6871 }
6872 
ZEND_METHOD(ReflectionEnum,getCases)6873 ZEND_METHOD(ReflectionEnum, getCases)
6874 {
6875 	reflection_object *intern;
6876 	zend_class_entry *ce;
6877 	zend_string *name;
6878 	zend_class_constant *constant;
6879 
6880 	if (zend_parse_parameters_none() == FAILURE) {
6881 		RETURN_THROWS();
6882 	}
6883 
6884 	GET_REFLECTION_OBJECT_PTR(ce);
6885 
6886 	array_init(return_value);
6887 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), name, constant) {
6888 		if (ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE) {
6889 			zval class_const;
6890 			reflection_enum_case_factory(ce, name, constant, &class_const);
6891 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &class_const);
6892 		}
6893 	} ZEND_HASH_FOREACH_END();
6894 }
6895 
ZEND_METHOD(ReflectionEnum,isBacked)6896 ZEND_METHOD(ReflectionEnum, isBacked)
6897 {
6898 	reflection_object *intern;
6899 	zend_class_entry *ce;
6900 
6901 	if (zend_parse_parameters_none() == FAILURE) {
6902 		RETURN_THROWS();
6903 	}
6904 
6905 	GET_REFLECTION_OBJECT_PTR(ce);
6906 	RETURN_BOOL(ce->enum_backing_type != IS_UNDEF);
6907 }
6908 
ZEND_METHOD(ReflectionEnum,getBackingType)6909 ZEND_METHOD(ReflectionEnum, getBackingType)
6910 {
6911 	reflection_object *intern;
6912 	zend_class_entry *ce;
6913 
6914 	if (zend_parse_parameters_none() == FAILURE) {
6915 		RETURN_THROWS();
6916 	}
6917 
6918 	GET_REFLECTION_OBJECT_PTR(ce);
6919 
6920 	if (ce->enum_backing_type == IS_UNDEF) {
6921 		RETURN_NULL();
6922 	} else {
6923 		zend_type type = ZEND_TYPE_INIT_CODE(ce->enum_backing_type, 0, 0);
6924 		reflection_type_factory(type, return_value, 0);
6925 	}
6926 }
6927 
ZEND_METHOD(ReflectionEnumUnitCase,__construct)6928 ZEND_METHOD(ReflectionEnumUnitCase, __construct)
6929 {
6930 	ZEND_MN(ReflectionClassConstant___construct)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
6931 	if (EG(exception)) {
6932 		RETURN_THROWS();
6933 	}
6934 
6935 	reflection_object *intern;
6936 	zend_class_constant *ref;
6937 
6938 	GET_REFLECTION_OBJECT_PTR(ref);
6939 
6940 	if (!(ZEND_CLASS_CONST_FLAGS(ref) & ZEND_CLASS_CONST_IS_CASE)) {
6941 		zval *case_name = reflection_prop_name(ZEND_THIS);
6942 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s is not a case", ZSTR_VAL(ref->ce->name), Z_STRVAL_P(case_name));
6943 		RETURN_THROWS();
6944 	}
6945 }
6946 
ZEND_METHOD(ReflectionEnumUnitCase,getEnum)6947 ZEND_METHOD(ReflectionEnumUnitCase, getEnum)
6948 {
6949 	reflection_object *intern;
6950 	zend_class_constant *ref;
6951 
6952 	if (zend_parse_parameters_none() == FAILURE) {
6953 		RETURN_THROWS();
6954 	}
6955 	GET_REFLECTION_OBJECT_PTR(ref);
6956 
6957 	zend_reflection_class_factory(ref->ce, return_value);
6958 }
6959 
ZEND_METHOD(ReflectionEnumBackedCase,__construct)6960 ZEND_METHOD(ReflectionEnumBackedCase, __construct)
6961 {
6962 	ZEND_MN(ReflectionEnumUnitCase___construct)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
6963 	if (EG(exception)) {
6964 		RETURN_THROWS();
6965 	}
6966 
6967 	reflection_object *intern;
6968 	zend_class_constant *ref;
6969 
6970 	GET_REFLECTION_OBJECT_PTR(ref);
6971 
6972 	if (ref->ce->enum_backing_type == IS_UNDEF) {
6973 		zval *case_name = reflection_prop_name(ZEND_THIS);
6974 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Enum case %s::%s is not a backed case", ZSTR_VAL(ref->ce->name), Z_STRVAL_P(case_name));
6975 		RETURN_THROWS();
6976 	}
6977 }
6978 
ZEND_METHOD(ReflectionEnumBackedCase,getBackingValue)6979 ZEND_METHOD(ReflectionEnumBackedCase, getBackingValue)
6980 {
6981 	reflection_object *intern;
6982 	zend_class_constant *ref;
6983 
6984 	if (zend_parse_parameters_none() == FAILURE) {
6985 		RETURN_THROWS();
6986 	}
6987 	GET_REFLECTION_OBJECT_PTR(ref);
6988 
6989 	if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
6990 		zval_update_constant_ex(&ref->value, ref->ce);
6991 		if (EG(exception)) {
6992 			return;
6993 		}
6994 	}
6995 
6996 	ZEND_ASSERT(intern->ce->enum_backing_type != IS_UNDEF);
6997 	zval *member_p = zend_enum_fetch_case_value(Z_OBJ(ref->value));
6998 
6999 	ZVAL_COPY_OR_DUP(return_value, member_p);
7000 }
7001 
7002 /* {{{ proto ReflectionFiber::__construct(Fiber $fiber) */
ZEND_METHOD(ReflectionFiber,__construct)7003 ZEND_METHOD(ReflectionFiber, __construct)
7004 {
7005 	zval *fiber, *object;
7006 	reflection_object *intern;
7007 
7008 	object = ZEND_THIS;
7009 	intern = Z_REFLECTION_P(object);
7010 
7011 	ZEND_PARSE_PARAMETERS_START(1, 1)
7012 		Z_PARAM_OBJECT_OF_CLASS(fiber, zend_ce_fiber)
7013 	ZEND_PARSE_PARAMETERS_END();
7014 
7015 	if (intern->ce) {
7016 		zval_ptr_dtor(&intern->obj);
7017 	}
7018 
7019 	intern->ref_type = REF_TYPE_FIBER;
7020 	ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(fiber));
7021 	intern->ce = zend_ce_fiber;
7022 }
7023 /* }}} */
7024 
ZEND_METHOD(ReflectionFiber,getFiber)7025 ZEND_METHOD(ReflectionFiber, getFiber)
7026 {
7027 	ZEND_PARSE_PARAMETERS_NONE();
7028 
7029 	RETURN_OBJ_COPY(Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj));
7030 }
7031 
7032 #define REFLECTION_CHECK_VALID_FIBER(fiber) do { \
7033 		if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_INIT || fiber->context.status == ZEND_FIBER_STATUS_DEAD) { \
7034 			zend_throw_error(NULL, "Cannot fetch information from a fiber that has not been started or is terminated"); \
7035 			RETURN_THROWS(); \
7036 		} \
7037 	} while (0)
7038 
ZEND_METHOD(ReflectionFiber,getTrace)7039 ZEND_METHOD(ReflectionFiber, getTrace)
7040 {
7041 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7042 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
7043 	zend_execute_data *prev_execute_data;
7044 
7045 	ZEND_PARSE_PARAMETERS_START(0, 1)
7046 		Z_PARAM_OPTIONAL
7047 		Z_PARAM_LONG(options);
7048 	ZEND_PARSE_PARAMETERS_END();
7049 
7050 	REFLECTION_CHECK_VALID_FIBER(fiber);
7051 
7052 	prev_execute_data = fiber->stack_bottom->prev_execute_data;
7053 	fiber->stack_bottom->prev_execute_data = NULL;
7054 
7055 	if (EG(active_fiber) != fiber) {
7056 		// No need to replace current execute data if within the current fiber.
7057 		EG(current_execute_data) = fiber->execute_data;
7058 	}
7059 
7060 	zend_fetch_debug_backtrace(return_value, 0, options, 0);
7061 
7062 	EG(current_execute_data) = execute_data; // Restore original execute data.
7063 	fiber->stack_bottom->prev_execute_data = prev_execute_data; // Restore prev execute data on fiber stack.
7064 }
7065 
ZEND_METHOD(ReflectionFiber,getExecutingLine)7066 ZEND_METHOD(ReflectionFiber, getExecutingLine)
7067 {
7068 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7069 	zend_execute_data *prev_execute_data;
7070 
7071 	ZEND_PARSE_PARAMETERS_NONE();
7072 
7073 	REFLECTION_CHECK_VALID_FIBER(fiber);
7074 
7075 	if (EG(active_fiber) == fiber) {
7076 		prev_execute_data = execute_data->prev_execute_data;
7077 	} else {
7078 		prev_execute_data = fiber->execute_data->prev_execute_data;
7079 	}
7080 
7081 	while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) {
7082 		prev_execute_data = prev_execute_data->prev_execute_data;
7083 	}
7084 	if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
7085 		RETURN_LONG(prev_execute_data->opline->lineno);
7086 	}
7087 	RETURN_NULL();
7088 }
7089 
ZEND_METHOD(ReflectionFiber,getExecutingFile)7090 ZEND_METHOD(ReflectionFiber, getExecutingFile)
7091 {
7092 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7093 	zend_execute_data *prev_execute_data;
7094 
7095 	ZEND_PARSE_PARAMETERS_NONE();
7096 
7097 	REFLECTION_CHECK_VALID_FIBER(fiber);
7098 
7099 	if (EG(active_fiber) == fiber) {
7100 		prev_execute_data = execute_data->prev_execute_data;
7101 	} else {
7102 		prev_execute_data = fiber->execute_data->prev_execute_data;
7103 	}
7104 
7105 	while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) {
7106 		prev_execute_data = prev_execute_data->prev_execute_data;
7107 	}
7108 	if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
7109 		RETURN_STR_COPY(prev_execute_data->func->op_array.filename);
7110 	}
7111 	RETURN_NULL();
7112 }
7113 
ZEND_METHOD(ReflectionFiber,getCallable)7114 ZEND_METHOD(ReflectionFiber, getCallable)
7115 {
7116 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7117 
7118 	ZEND_PARSE_PARAMETERS_NONE();
7119 
7120 	if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
7121 		zend_throw_error(NULL, "Cannot fetch the callable from a fiber that has terminated"); \
7122 		RETURN_THROWS();
7123 	}
7124 
7125 	RETURN_COPY(&fiber->fci.function_name);
7126 }
7127 
7128 /* {{{ _reflection_write_property */
_reflection_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)7129 static zval *_reflection_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
7130 {
7131 	if (zend_hash_exists(&object->ce->properties_info, name)
7132 		&& (zend_string_equals_literal(name, "name") || zend_string_equals_literal(name, "class")))
7133 	{
7134 		zend_throw_exception_ex(reflection_exception_ptr, 0,
7135 			"Cannot set read-only property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
7136 		return &EG(uninitialized_zval);
7137 	}
7138 	else
7139 	{
7140 		return zend_std_write_property(object, name, value, cache_slot);
7141 	}
7142 }
7143 /* }}} */
7144 
PHP_MINIT_FUNCTION(reflection)7145 PHP_MINIT_FUNCTION(reflection) /* {{{ */
7146 {
7147 	memcpy(&reflection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
7148 	reflection_object_handlers.offset = XtOffsetOf(reflection_object, zo);
7149 	reflection_object_handlers.free_obj = reflection_free_objects_storage;
7150 	reflection_object_handlers.clone_obj = NULL;
7151 	reflection_object_handlers.write_property = _reflection_write_property;
7152 	reflection_object_handlers.get_gc = reflection_get_gc;
7153 
7154 	reflection_exception_ptr = register_class_ReflectionException(zend_ce_exception);
7155 
7156 	reflection_ptr = register_class_Reflection();
7157 
7158 	reflector_ptr = register_class_Reflector(zend_ce_stringable);
7159 
7160 	reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr);
7161 	reflection_function_abstract_ptr->create_object = reflection_objects_new;
7162 
7163 	reflection_function_ptr = register_class_ReflectionFunction(reflection_function_abstract_ptr);
7164 	reflection_function_ptr->create_object = reflection_objects_new;
7165 
7166 	reflection_generator_ptr = register_class_ReflectionGenerator();
7167 	reflection_generator_ptr->create_object = reflection_objects_new;
7168 
7169 	reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr);
7170 	reflection_parameter_ptr->create_object = reflection_objects_new;
7171 
7172 	reflection_type_ptr = register_class_ReflectionType(zend_ce_stringable);
7173 	reflection_type_ptr->create_object = reflection_objects_new;
7174 
7175 	reflection_named_type_ptr = register_class_ReflectionNamedType(reflection_type_ptr);
7176 	reflection_named_type_ptr->create_object = reflection_objects_new;
7177 
7178 	reflection_union_type_ptr = register_class_ReflectionUnionType(reflection_type_ptr);
7179 	reflection_union_type_ptr->create_object = reflection_objects_new;
7180 
7181 	reflection_intersection_type_ptr = register_class_ReflectionIntersectionType(reflection_type_ptr);
7182 	reflection_intersection_type_ptr->create_object = reflection_objects_new;
7183 
7184 	reflection_method_ptr = register_class_ReflectionMethod(reflection_function_abstract_ptr);
7185 	reflection_method_ptr->create_object = reflection_objects_new;
7186 
7187 	reflection_class_ptr = register_class_ReflectionClass(reflector_ptr);
7188 	reflection_class_ptr->create_object = reflection_objects_new;
7189 
7190 	reflection_object_ptr = register_class_ReflectionObject(reflection_class_ptr);
7191 	reflection_object_ptr->create_object = reflection_objects_new;
7192 
7193 	reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr);
7194 	reflection_property_ptr->create_object = reflection_objects_new;
7195 
7196 	reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr);
7197 	reflection_class_constant_ptr->create_object = reflection_objects_new;
7198 
7199 	reflection_extension_ptr = register_class_ReflectionExtension(reflector_ptr);
7200 	reflection_extension_ptr->create_object = reflection_objects_new;
7201 
7202 	reflection_zend_extension_ptr = register_class_ReflectionZendExtension(reflector_ptr);
7203 	reflection_zend_extension_ptr->create_object = reflection_objects_new;
7204 
7205 	reflection_reference_ptr = register_class_ReflectionReference();
7206 	reflection_reference_ptr->create_object = reflection_objects_new;
7207 
7208 	reflection_attribute_ptr = register_class_ReflectionAttribute(reflector_ptr);
7209 	reflection_attribute_ptr->create_object = reflection_objects_new;
7210 
7211 	reflection_enum_ptr = register_class_ReflectionEnum(reflection_class_ptr);
7212 	reflection_enum_ptr->create_object = reflection_objects_new;
7213 
7214 	reflection_enum_unit_case_ptr = register_class_ReflectionEnumUnitCase(reflection_class_constant_ptr);
7215 	reflection_enum_unit_case_ptr->create_object = reflection_objects_new;
7216 
7217 	reflection_enum_backed_case_ptr = register_class_ReflectionEnumBackedCase(reflection_enum_unit_case_ptr);
7218 	reflection_enum_backed_case_ptr->create_object = reflection_objects_new;
7219 
7220 	reflection_fiber_ptr = register_class_ReflectionFiber();
7221 	reflection_fiber_ptr->create_object = reflection_objects_new;
7222 
7223 	REFLECTION_G(key_initialized) = 0;
7224 
7225 	return SUCCESS;
7226 } /* }}} */
7227 
PHP_MINFO_FUNCTION(reflection)7228 PHP_MINFO_FUNCTION(reflection) /* {{{ */
7229 {
7230 	php_info_print_table_start();
7231 	php_info_print_table_row(2, "Reflection", "enabled");
7232 	php_info_print_table_end();
7233 } /* }}} */
7234 
7235 zend_module_entry reflection_module_entry = { /* {{{ */
7236 	STANDARD_MODULE_HEADER,
7237 	"Reflection",
7238 	NULL,
7239 	PHP_MINIT(reflection),
7240 	NULL,
7241 	NULL,
7242 	NULL,
7243 	PHP_MINFO(reflection),
7244 	PHP_REFLECTION_VERSION,
7245 	ZEND_MODULE_GLOBALS(reflection),
7246 	NULL,
7247 	NULL,
7248 	NULL,
7249 	STANDARD_MODULE_PROPERTIES_EX
7250 }; /* }}} */
7251