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