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