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