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