xref: /php-src/ext/reflection/php_reflection.c (revision 8094bd1b)
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 
2255 	object = ZEND_THIS;
2256 	intern = Z_REFLECTION_P(object);
2257 
2258 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) {
2259 		RETURN_THROWS();
2260 	}
2261 
2262 	if (intern->ce) {
2263 		zval_ptr_dtor(&intern->obj);
2264 	}
2265 
2266 	intern->ref_type = REF_TYPE_GENERATOR;
2267 	ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(generator));
2268 	intern->ce = zend_ce_generator;
2269 }
2270 /* }}} */
2271 
2272 #define REFLECTION_CHECK_VALID_GENERATOR(ex) \
2273 	if (!ex) { \
2274 		_DO_THROW("Cannot fetch information from a terminated Generator"); \
2275 		RETURN_THROWS(); \
2276 	}
2277 
2278 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getTrace)2279 ZEND_METHOD(ReflectionGenerator, getTrace)
2280 {
2281 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
2282 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2283 	zend_generator *root_generator;
2284 	zend_execute_data *ex_backup = EG(current_execute_data);
2285 	zend_execute_data *ex = generator->execute_data;
2286 	zend_execute_data *root_prev = NULL, *cur_prev;
2287 
2288 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &options) == FAILURE) {
2289 		RETURN_THROWS();
2290 	}
2291 
2292 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2293 
2294 	root_generator = zend_generator_get_current(generator);
2295 
2296 	cur_prev = generator->execute_data->prev_execute_data;
2297 	if (generator == root_generator) {
2298 		generator->execute_data->prev_execute_data = NULL;
2299 	} else {
2300 		root_prev = root_generator->execute_data->prev_execute_data;
2301 		generator->execute_fake.prev_execute_data = NULL;
2302 		root_generator->execute_data->prev_execute_data = &generator->execute_fake;
2303 	}
2304 
2305 	EG(current_execute_data) = root_generator->execute_data;
2306 	zend_fetch_debug_backtrace(return_value, 0, options, 0);
2307 	EG(current_execute_data) = ex_backup;
2308 
2309 	root_generator->execute_data->prev_execute_data = root_prev;
2310 	generator->execute_data->prev_execute_data = cur_prev;
2311 }
2312 /* }}} */
2313 
2314 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getExecutingLine)2315 ZEND_METHOD(ReflectionGenerator, getExecutingLine)
2316 {
2317 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2318 	zend_execute_data *ex = generator->execute_data;
2319 
2320 	if (zend_parse_parameters_none() == FAILURE) {
2321 		RETURN_THROWS();
2322 	}
2323 
2324 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2325 
2326 	ZVAL_LONG(return_value, ex->opline->lineno);
2327 }
2328 /* }}} */
2329 
2330 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getExecutingFile)2331 ZEND_METHOD(ReflectionGenerator, getExecutingFile)
2332 {
2333 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2334 	zend_execute_data *ex = generator->execute_data;
2335 
2336 	if (zend_parse_parameters_none() == FAILURE) {
2337 		RETURN_THROWS();
2338 	}
2339 
2340 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2341 
2342 	ZVAL_STR_COPY(return_value, ex->func->op_array.filename);
2343 }
2344 /* }}} */
2345 
2346 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getFunction)2347 ZEND_METHOD(ReflectionGenerator, getFunction)
2348 {
2349 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2350 	zend_function *func = generator->func;
2351 
2352 	if (zend_parse_parameters_none() == FAILURE) {
2353 		RETURN_THROWS();
2354 	}
2355 
2356 	if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
2357 		zval closure;
2358 		ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(func));
2359 		reflection_function_factory(func, &closure, return_value);
2360 	} else if (func->op_array.scope) {
2361 		reflection_method_factory(func->op_array.scope, func, NULL, return_value);
2362 	} else {
2363 		reflection_function_factory(func, NULL, return_value);
2364 	}
2365 }
2366 /* }}} */
2367 
2368 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getThis)2369 ZEND_METHOD(ReflectionGenerator, getThis)
2370 {
2371 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2372 	zend_execute_data *ex = generator->execute_data;
2373 
2374 	if (zend_parse_parameters_none() == FAILURE) {
2375 		RETURN_THROWS();
2376 	}
2377 
2378 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2379 
2380 	if (Z_TYPE(ex->This) == IS_OBJECT) {
2381 		RETURN_OBJ_COPY(Z_OBJ(ex->This));
2382 	} else {
2383 		RETURN_NULL();
2384 	}
2385 }
2386 /* }}} */
2387 
2388 /* {{{ */
ZEND_METHOD(ReflectionGenerator,getExecutingGenerator)2389 ZEND_METHOD(ReflectionGenerator, getExecutingGenerator)
2390 {
2391 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2392 	zend_execute_data *ex = generator->execute_data;
2393 	zend_generator *current;
2394 
2395 	if (zend_parse_parameters_none() == FAILURE) {
2396 		RETURN_THROWS();
2397 	}
2398 
2399 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2400 
2401 	current = zend_generator_get_current(generator);
2402 	RETURN_OBJ_COPY(&current->std);
2403 }
2404 /* }}} */
2405 
2406 /* {{{ Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHOD(ReflectionParameter,__construct)2407 ZEND_METHOD(ReflectionParameter, __construct)
2408 {
2409 	parameter_reference *ref;
2410 	zval *reference;
2411 	zend_string *arg_name = NULL;
2412 	zend_long position;
2413 	zval *object;
2414 	zval *prop_name;
2415 	reflection_object *intern;
2416 	zend_function *fptr;
2417 	struct _zend_arg_info *arg_info;
2418 	uint32_t num_args;
2419 	zend_class_entry *ce = NULL;
2420 	bool is_closure = 0;
2421 
2422 	ZEND_PARSE_PARAMETERS_START(2, 2)
2423 		Z_PARAM_ZVAL(reference)
2424 		Z_PARAM_STR_OR_LONG(arg_name, position)
2425 	ZEND_PARSE_PARAMETERS_END();
2426 
2427 	object = ZEND_THIS;
2428 	intern = Z_REFLECTION_P(object);
2429 
2430 	/* First, find the function */
2431 	switch (Z_TYPE_P(reference)) {
2432 		case IS_STRING:
2433 			{
2434 				zend_string *lcname = zend_string_tolower(Z_STR_P(reference));
2435 				fptr = zend_hash_find_ptr(EG(function_table), lcname);
2436 				zend_string_release(lcname);
2437 				if (!fptr) {
2438 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2439 						"Function %s() does not exist", Z_STRVAL_P(reference));
2440 					RETURN_THROWS();
2441 				}
2442 				ce = fptr->common.scope;
2443 			}
2444 			break;
2445 
2446 		case IS_ARRAY: {
2447 				zval *classref;
2448 				zval *method;
2449 				zend_string *name, *lcname;
2450 
2451 				if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
2452 					|| ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL))
2453 				{
2454 					_DO_THROW("Expected array($object, $method) or array($classname, $method)");
2455 					RETURN_THROWS();
2456 				}
2457 
2458 				if (Z_TYPE_P(classref) == IS_OBJECT) {
2459 					ce = Z_OBJCE_P(classref);
2460 				} else {
2461 					name = zval_try_get_string(classref);
2462 					if (UNEXPECTED(!name)) {
2463 						return;
2464 					}
2465 					if ((ce = zend_lookup_class(name)) == NULL) {
2466 						zend_throw_exception_ex(reflection_exception_ptr, 0,
2467 								"Class \"%s\" does not exist", ZSTR_VAL(name));
2468 						zend_string_release(name);
2469 						RETURN_THROWS();
2470 					}
2471 					zend_string_release(name);
2472 				}
2473 
2474 				name = zval_try_get_string(method);
2475 				if (UNEXPECTED(!name)) {
2476 					return;
2477 				}
2478 
2479 				lcname = zend_string_tolower(name);
2480 				if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname)
2481 					&& (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
2482 				{
2483 					/* nothing to do. don't set is_closure since is the invoke handler,
2484 					   not the closure itself */
2485 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
2486 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2487 						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
2488 					zend_string_release(name);
2489 					zend_string_release(lcname);
2490 					RETURN_THROWS();
2491 				}
2492 				zend_string_release(name);
2493 				zend_string_release(lcname);
2494 			}
2495 			break;
2496 
2497 		case IS_OBJECT: {
2498 				ce = Z_OBJCE_P(reference);
2499 
2500 				if (instanceof_function(ce, zend_ce_closure)) {
2501 					fptr = (zend_function *)zend_get_closure_method_def(Z_OBJ_P(reference));
2502 					Z_ADDREF_P(reference);
2503 					is_closure = 1;
2504 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) {
2505 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2506 						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME);
2507 					RETURN_THROWS();
2508 				}
2509 			}
2510 			break;
2511 
2512 		default:
2513 			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));
2514 			RETURN_THROWS();
2515 	}
2516 
2517 	/* Now, search for the parameter */
2518 	arg_info = fptr->common.arg_info;
2519 	num_args = fptr->common.num_args;
2520 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2521 		num_args++;
2522 	}
2523 	if (arg_name != NULL) {
2524 		uint32_t i;
2525 		position = -1;
2526 
2527 		if (has_internal_arg_info(fptr)) {
2528 			for (i = 0; i < num_args; i++) {
2529 				if (arg_info[i].name) {
2530 					if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, ZSTR_VAL(arg_name)) == 0) {
2531 						position = i;
2532 						break;
2533 					}
2534 				}
2535 			}
2536 		} else {
2537 			for (i = 0; i < num_args; i++) {
2538 				if (arg_info[i].name) {
2539 					if (zend_string_equals(arg_name, arg_info[i].name)) {
2540 						position = i;
2541 						break;
2542 					}
2543 				}
2544 			}
2545 		}
2546 		if (position == -1) {
2547 			_DO_THROW("The parameter specified by its name could not be found");
2548 			goto failure;
2549 		}
2550 	} else {
2551 		if (position < 0) {
2552 			zend_argument_value_error(2, "must be greater than or equal to 0");
2553 			goto failure;
2554 		}
2555 		if (position >= num_args) {
2556 			_DO_THROW("The parameter specified by its offset could not be found");
2557 			goto failure;
2558 		}
2559 	}
2560 
2561 	ref = (parameter_reference*) emalloc(sizeof(parameter_reference));
2562 	ref->arg_info = &arg_info[position];
2563 	ref->offset = (uint32_t)position;
2564 	ref->required = (uint32_t)position < fptr->common.required_num_args;
2565 	ref->fptr = fptr;
2566 	/* TODO: copy fptr */
2567 	intern->ptr = ref;
2568 	intern->ref_type = REF_TYPE_PARAMETER;
2569 	intern->ce = ce;
2570 	if (reference && is_closure) {
2571 		ZVAL_COPY_VALUE(&intern->obj, reference);
2572 	}
2573 
2574 	prop_name = reflection_prop_name(object);
2575 	if (has_internal_arg_info(fptr)) {
2576 		ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)[position].name);
2577 	} else {
2578 		ZVAL_STR_COPY(prop_name, arg_info[position].name);
2579 	}
2580 	return;
2581 
2582 failure:
2583 	if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2584 		zend_string_release_ex(fptr->common.function_name, 0);
2585 		zend_free_trampoline(fptr);
2586 	}
2587 	if (is_closure) {
2588 		zval_ptr_dtor(reference);
2589 	}
2590 	RETURN_THROWS();
2591 }
2592 /* }}} */
2593 
2594 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionParameter,__toString)2595 ZEND_METHOD(ReflectionParameter, __toString)
2596 {
2597 	reflection_object *intern;
2598 	parameter_reference *param;
2599 	smart_str str = {0};
2600 
2601 	if (zend_parse_parameters_none() == FAILURE) {
2602 		RETURN_THROWS();
2603 	}
2604 	GET_REFLECTION_OBJECT_PTR(param);
2605 	_parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "");
2606 	RETURN_STR(smart_str_extract(&str));
2607 }
2608 
2609 /* }}} */
2610 
2611 /* {{{ Returns this parameters's name */
ZEND_METHOD(ReflectionParameter,getName)2612 ZEND_METHOD(ReflectionParameter, getName)
2613 {
2614 	reflection_object *intern;
2615 	parameter_reference *param;
2616 
2617 	if (zend_parse_parameters_none() == FAILURE) {
2618 		RETURN_THROWS();
2619 	}
2620 
2621 	GET_REFLECTION_OBJECT_PTR(param);
2622 	if (has_internal_arg_info(param->fptr)) {
2623 		RETURN_STRING(((zend_internal_arg_info *) param->arg_info)->name);
2624 	} else {
2625 		RETURN_STR_COPY(param->arg_info->name);
2626 	}
2627 }
2628 /* }}} */
2629 
2630 /* {{{ Returns the ReflectionFunction for the function of this parameter */
ZEND_METHOD(ReflectionParameter,getDeclaringFunction)2631 ZEND_METHOD(ReflectionParameter, getDeclaringFunction)
2632 {
2633 	reflection_object *intern;
2634 	parameter_reference *param;
2635 
2636 	if (zend_parse_parameters_none() == FAILURE) {
2637 		RETURN_THROWS();
2638 	}
2639 	GET_REFLECTION_OBJECT_PTR(param);
2640 
2641 	if (!param->fptr->common.scope) {
2642 		reflection_function_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2643 	} else {
2644 		reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2645 	}
2646 }
2647 /* }}} */
2648 
2649 /* {{{ Returns in which class this parameter is defined (not the type of the parameter) */
ZEND_METHOD(ReflectionParameter,getDeclaringClass)2650 ZEND_METHOD(ReflectionParameter, getDeclaringClass)
2651 {
2652 	reflection_object *intern;
2653 	parameter_reference *param;
2654 
2655 	if (zend_parse_parameters_none() == FAILURE) {
2656 		RETURN_THROWS();
2657 	}
2658 	GET_REFLECTION_OBJECT_PTR(param);
2659 
2660 	if (param->fptr->common.scope) {
2661 		zend_reflection_class_factory(param->fptr->common.scope, return_value);
2662 	}
2663 }
2664 /* }}} */
2665 
2666 /* {{{ Returns this parameters's class hint or NULL if there is none */
ZEND_METHOD(ReflectionParameter,getClass)2667 ZEND_METHOD(ReflectionParameter, getClass)
2668 {
2669 	reflection_object *intern;
2670 	parameter_reference *param;
2671 	zend_class_entry *ce;
2672 
2673 	if (zend_parse_parameters_none() == FAILURE) {
2674 		RETURN_THROWS();
2675 	}
2676 	GET_REFLECTION_OBJECT_PTR(param);
2677 
2678 	// TODO: This is going to return null for union types, which is rather odd.
2679 	if (ZEND_TYPE_HAS_NAME(param->arg_info->type)) {
2680 		/* Class name is stored as a string, we might also get "self" or "parent"
2681 		 * - For "self", simply use the function scope. If scope is NULL then
2682 		 *   the function is global and thus self does not make any sense
2683 		 *
2684 		 * - For "parent", use the function scope's parent. If scope is NULL then
2685 		 *   the function is global and thus parent does not make any sense.
2686 		 *   If the parent is NULL then the class does not extend anything and
2687 		 *   thus parent does not make any sense, either.
2688 		 *
2689 		 * TODO: Think about moving these checks to the compiler or some sort of
2690 		 * lint-mode.
2691 		 */
2692 		zend_string *class_name;
2693 
2694 		class_name = ZEND_TYPE_NAME(param->arg_info->type);
2695 		if (zend_string_equals_literal_ci(class_name, "self")) {
2696 			ce = param->fptr->common.scope;
2697 			if (!ce) {
2698 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2699 					"Parameter uses \"self\" as type but function is not a class member");
2700 				RETURN_THROWS();
2701 			}
2702 		} else if (zend_string_equals_literal_ci(class_name, "parent")) {
2703 			ce = param->fptr->common.scope;
2704 			if (!ce) {
2705 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2706 					"Parameter uses \"parent\" as type but function is not a class member");
2707 				RETURN_THROWS();
2708 			}
2709 			if (!ce->parent) {
2710 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2711 					"Parameter uses \"parent\" as type although class does not have a parent");
2712 				RETURN_THROWS();
2713 			}
2714 			ce = ce->parent;
2715 		} else {
2716 			ce = zend_lookup_class(class_name);
2717 			if (!ce) {
2718 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2719 					"Class \"%s\" does not exist", ZSTR_VAL(class_name));
2720 				RETURN_THROWS();
2721 			}
2722 		}
2723 		zend_reflection_class_factory(ce, return_value);
2724 	}
2725 }
2726 /* }}} */
2727 
2728 /* {{{ Returns whether parameter has a type */
ZEND_METHOD(ReflectionParameter,hasType)2729 ZEND_METHOD(ReflectionParameter, hasType)
2730 {
2731 	reflection_object *intern;
2732 	parameter_reference *param;
2733 
2734 	if (zend_parse_parameters_none() == FAILURE) {
2735 		RETURN_THROWS();
2736 	}
2737 	GET_REFLECTION_OBJECT_PTR(param);
2738 
2739 	RETVAL_BOOL(ZEND_TYPE_IS_SET(param->arg_info->type));
2740 }
2741 /* }}} */
2742 
2743 /* {{{ Returns the type associated with the parameter */
ZEND_METHOD(ReflectionParameter,getType)2744 ZEND_METHOD(ReflectionParameter, getType)
2745 {
2746 	reflection_object *intern;
2747 	parameter_reference *param;
2748 
2749 	if (zend_parse_parameters_none() == FAILURE) {
2750 		RETURN_THROWS();
2751 	}
2752 	GET_REFLECTION_OBJECT_PTR(param);
2753 
2754 	if (!ZEND_TYPE_IS_SET(param->arg_info->type)) {
2755 		RETURN_NULL();
2756 	}
2757 	reflection_type_factory(param->arg_info->type, return_value, 1);
2758 }
2759 /* }}} */
2760 
2761 /* {{{ Returns whether parameter MUST be an array */
ZEND_METHOD(ReflectionParameter,isArray)2762 ZEND_METHOD(ReflectionParameter, isArray)
2763 {
2764 	reflection_object *intern;
2765 	parameter_reference *param;
2766 	uint32_t type_mask;
2767 
2768 	if (zend_parse_parameters_none() == FAILURE) {
2769 		RETURN_THROWS();
2770 	}
2771 	GET_REFLECTION_OBJECT_PTR(param);
2772 
2773 	/* BC For iterable */
2774 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(param->arg_info->type)) {
2775 		RETURN_FALSE;
2776 	}
2777 
2778 	type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(param->arg_info->type);
2779 	RETVAL_BOOL(type_mask == MAY_BE_ARRAY);
2780 }
2781 /* }}} */
2782 
2783 /* {{{ Returns whether parameter MUST be callable */
ZEND_METHOD(ReflectionParameter,isCallable)2784 ZEND_METHOD(ReflectionParameter, isCallable)
2785 {
2786 	reflection_object *intern;
2787 	parameter_reference *param;
2788 	uint32_t type_mask;
2789 
2790 	if (zend_parse_parameters_none() == FAILURE) {
2791 		RETURN_THROWS();
2792 	}
2793 	GET_REFLECTION_OBJECT_PTR(param);
2794 
2795 	type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(param->arg_info->type);
2796 	RETVAL_BOOL(type_mask == MAY_BE_CALLABLE);
2797 }
2798 /* }}} */
2799 
2800 /* {{{ Returns whether NULL is allowed as this parameters's value */
ZEND_METHOD(ReflectionParameter,allowsNull)2801 ZEND_METHOD(ReflectionParameter, allowsNull)
2802 {
2803 	reflection_object *intern;
2804 	parameter_reference *param;
2805 
2806 	if (zend_parse_parameters_none() == FAILURE) {
2807 		RETURN_THROWS();
2808 	}
2809 	GET_REFLECTION_OBJECT_PTR(param);
2810 
2811 	RETVAL_BOOL(!ZEND_TYPE_IS_SET(param->arg_info->type)
2812 		|| ZEND_TYPE_ALLOW_NULL(param->arg_info->type));
2813 }
2814 /* }}} */
2815 
2816 /* {{{ Returns whether this parameters is passed to by reference */
ZEND_METHOD(ReflectionParameter,isPassedByReference)2817 ZEND_METHOD(ReflectionParameter, isPassedByReference)
2818 {
2819 	reflection_object *intern;
2820 	parameter_reference *param;
2821 
2822 	if (zend_parse_parameters_none() == FAILURE) {
2823 		RETURN_THROWS();
2824 	}
2825 	GET_REFLECTION_OBJECT_PTR(param);
2826 
2827 	RETVAL_BOOL(ZEND_ARG_SEND_MODE(param->arg_info));
2828 }
2829 /* }}} */
2830 
2831 /* {{{ Returns whether this parameter can be passed by value */
ZEND_METHOD(ReflectionParameter,canBePassedByValue)2832 ZEND_METHOD(ReflectionParameter, canBePassedByValue)
2833 {
2834 	reflection_object *intern;
2835 	parameter_reference *param;
2836 
2837 	if (zend_parse_parameters_none() == FAILURE) {
2838 		RETURN_THROWS();
2839 	}
2840 	GET_REFLECTION_OBJECT_PTR(param);
2841 
2842 	/* true if it's ZEND_SEND_BY_VAL or ZEND_SEND_PREFER_REF */
2843 	RETVAL_BOOL(ZEND_ARG_SEND_MODE(param->arg_info) != ZEND_SEND_BY_REF);
2844 }
2845 /* }}} */
2846 
2847 /* {{{ Get parameter attributes. */
ZEND_METHOD(ReflectionParameter,getAttributes)2848 ZEND_METHOD(ReflectionParameter, getAttributes)
2849 {
2850 	reflection_object *intern;
2851 	parameter_reference *param;
2852 
2853 	GET_REFLECTION_OBJECT_PTR(param);
2854 
2855 	HashTable *attributes = param->fptr->common.attributes;
2856 	zend_class_entry *scope = param->fptr->common.scope;
2857 
2858 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2859 		attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER,
2860 		param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL);
2861 }
2862 
2863 /* {{{ Returns whether this parameter is an optional parameter */
ZEND_METHOD(ReflectionParameter,getPosition)2864 ZEND_METHOD(ReflectionParameter, getPosition)
2865 {
2866 	reflection_object *intern;
2867 	parameter_reference *param;
2868 
2869 	if (zend_parse_parameters_none() == FAILURE) {
2870 		RETURN_THROWS();
2871 	}
2872 	GET_REFLECTION_OBJECT_PTR(param);
2873 
2874 	RETVAL_LONG(param->offset);
2875 }
2876 /* }}} */
2877 
2878 /* {{{ Returns whether this parameter is an optional parameter */
ZEND_METHOD(ReflectionParameter,isOptional)2879 ZEND_METHOD(ReflectionParameter, isOptional)
2880 {
2881 	reflection_object *intern;
2882 	parameter_reference *param;
2883 
2884 	if (zend_parse_parameters_none() == FAILURE) {
2885 		RETURN_THROWS();
2886 	}
2887 	GET_REFLECTION_OBJECT_PTR(param);
2888 
2889 	RETVAL_BOOL(!param->required);
2890 }
2891 /* }}} */
2892 
2893 /* {{{ Returns whether the default value of this parameter is available */
ZEND_METHOD(ReflectionParameter,isDefaultValueAvailable)2894 ZEND_METHOD(ReflectionParameter, isDefaultValueAvailable)
2895 {
2896 	reflection_object *intern;
2897 	parameter_reference *param;
2898 
2899 	if (zend_parse_parameters_none() == FAILURE) {
2900 		RETURN_THROWS();
2901 	}
2902 
2903 	GET_REFLECTION_OBJECT_PTR(param);
2904 
2905 	if (param->fptr->type == ZEND_INTERNAL_FUNCTION) {
2906 		RETURN_BOOL(!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)
2907 			&& ((zend_internal_arg_info*) (param->arg_info))->default_value);
2908 	} else {
2909 		zval *default_value = get_default_from_recv((zend_op_array *)param->fptr, param->offset);
2910 		RETURN_BOOL(default_value != NULL);
2911 	}
2912 }
2913 /* }}} */
2914 
2915 /* {{{ Returns the default value of this parameter or throws an exception */
ZEND_METHOD(ReflectionParameter,getDefaultValue)2916 ZEND_METHOD(ReflectionParameter, getDefaultValue)
2917 {
2918 	reflection_object *intern;
2919 	parameter_reference *param;
2920 
2921 	if (zend_parse_parameters_none() == FAILURE) {
2922 		RETURN_THROWS();
2923 	}
2924 
2925 	GET_REFLECTION_OBJECT_PTR(param);
2926 
2927 	if (get_parameter_default(return_value, param) == FAILURE) {
2928 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2929 			"Internal error: Failed to retrieve the default value");
2930 		RETURN_THROWS();
2931 	}
2932 
2933 	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
2934 		zval_update_constant_ex(return_value, param->fptr->common.scope);
2935 	}
2936 }
2937 /* }}} */
2938 
2939 /* {{{ Returns whether the default value of this parameter is constant */
ZEND_METHOD(ReflectionParameter,isDefaultValueConstant)2940 ZEND_METHOD(ReflectionParameter, isDefaultValueConstant)
2941 {
2942 	reflection_object *intern;
2943 	parameter_reference *param;
2944 
2945 	if (zend_parse_parameters_none() == FAILURE) {
2946 		RETURN_THROWS();
2947 	}
2948 
2949 	GET_REFLECTION_OBJECT_PTR(param);
2950 
2951 	zval default_value;
2952 	if (get_parameter_default(&default_value, param) == FAILURE) {
2953 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2954 			"Internal error: Failed to retrieve the default value");
2955 		RETURN_THROWS();
2956 	}
2957 
2958 	if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
2959 		zend_ast *ast = Z_ASTVAL(default_value);
2960 		RETVAL_BOOL(ast->kind == ZEND_AST_CONSTANT
2961 			|| ast->kind == ZEND_AST_CONSTANT_CLASS
2962 			|| ast->kind == ZEND_AST_CLASS_CONST);
2963 	} else {
2964 		RETVAL_FALSE;
2965 	}
2966 
2967 	zval_ptr_dtor_nogc(&default_value);
2968 }
2969 /* }}} */
2970 
2971 /* {{{ Returns the default value's constant name if default value is constant or null */
ZEND_METHOD(ReflectionParameter,getDefaultValueConstantName)2972 ZEND_METHOD(ReflectionParameter, getDefaultValueConstantName)
2973 {
2974 	reflection_object *intern;
2975 	parameter_reference *param;
2976 
2977 	if (zend_parse_parameters_none() == FAILURE) {
2978 		RETURN_THROWS();
2979 	}
2980 
2981 	GET_REFLECTION_OBJECT_PTR(param);
2982 
2983 	zval default_value;
2984 	if (get_parameter_default(&default_value, param) == FAILURE) {
2985 		zend_throw_exception_ex(reflection_exception_ptr, 0,
2986 			"Internal error: Failed to retrieve the default value");
2987 		RETURN_THROWS();
2988 	}
2989 
2990 	if (Z_TYPE(default_value) != IS_CONSTANT_AST) {
2991 		zval_ptr_dtor_nogc(&default_value);
2992 		RETURN_NULL();
2993 	}
2994 
2995 	zend_ast *ast = Z_ASTVAL(default_value);
2996 	if (ast->kind == ZEND_AST_CONSTANT) {
2997 		RETVAL_STR_COPY(zend_ast_get_constant_name(ast));
2998 	} else if (ast->kind == ZEND_AST_CONSTANT_CLASS) {
2999 		RETVAL_STRINGL("__CLASS__", sizeof("__CLASS__")-1);
3000 	} else if (ast->kind == ZEND_AST_CLASS_CONST) {
3001 		zend_string *class_name = zend_ast_get_str(ast->child[0]);
3002 		zend_string *const_name = zend_ast_get_str(ast->child[1]);
3003 		RETVAL_NEW_STR(zend_string_concat3(
3004 			ZSTR_VAL(class_name), ZSTR_LEN(class_name),
3005 			"::", sizeof("::")-1,
3006 			ZSTR_VAL(const_name), ZSTR_LEN(const_name)));
3007 	} else {
3008 		RETVAL_NULL();
3009 	}
3010 	zval_ptr_dtor_nogc(&default_value);
3011 }
3012 
3013 /* {{{ Returns whether this parameter is a variadic parameter */
ZEND_METHOD(ReflectionParameter,isVariadic)3014 ZEND_METHOD(ReflectionParameter, isVariadic)
3015 {
3016 	reflection_object *intern;
3017 	parameter_reference *param;
3018 
3019 	if (zend_parse_parameters_none() == FAILURE) {
3020 		RETURN_THROWS();
3021 	}
3022 	GET_REFLECTION_OBJECT_PTR(param);
3023 
3024 	RETVAL_BOOL(ZEND_ARG_IS_VARIADIC(param->arg_info));
3025 }
3026 /* }}} */
3027 
3028 /* {{{ Returns this constructor parameter has been promoted to a property */
ZEND_METHOD(ReflectionParameter,isPromoted)3029 ZEND_METHOD(ReflectionParameter, isPromoted)
3030 {
3031 	reflection_object *intern;
3032 	parameter_reference *param;
3033 
3034 	if (zend_parse_parameters_none() == FAILURE) {
3035 		RETURN_THROWS();
3036 	}
3037 	GET_REFLECTION_OBJECT_PTR(param);
3038 
3039 	RETVAL_BOOL(ZEND_ARG_IS_PROMOTED(param->arg_info));
3040 }
3041 /* }}} */
3042 
3043 /* {{{ Returns whether parameter MAY be null */
ZEND_METHOD(ReflectionType,allowsNull)3044 ZEND_METHOD(ReflectionType, allowsNull)
3045 {
3046 	reflection_object *intern;
3047 	type_reference *param;
3048 
3049 	if (zend_parse_parameters_none() == FAILURE) {
3050 		RETURN_THROWS();
3051 	}
3052 	GET_REFLECTION_OBJECT_PTR(param);
3053 
3054 	RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->type));
3055 }
3056 /* }}} */
3057 
3058 /* For BC with iterable for named types */
zend_named_reflection_type_to_string(zend_type type)3059 static zend_string *zend_named_reflection_type_to_string(zend_type type) {
3060 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(type)) {
3061 		zend_string *iterable = ZSTR_KNOWN(ZEND_STR_ITERABLE);
3062 		if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_NULL) {
3063 			return zend_string_concat2("?", strlen("?"), ZSTR_VAL(iterable), ZSTR_LEN(iterable));
3064 		}
3065 		return iterable;
3066 	}
3067 	return zend_type_to_string(type);
3068 }
3069 
zend_type_to_string_without_null(zend_type type)3070 static zend_string *zend_type_to_string_without_null(zend_type type) {
3071 	ZEND_TYPE_FULL_MASK(type) &= ~MAY_BE_NULL;
3072 	return zend_named_reflection_type_to_string(type);
3073 }
3074 
3075 /* {{{ Return the text of the type hint */
ZEND_METHOD(ReflectionType,__toString)3076 ZEND_METHOD(ReflectionType, __toString)
3077 {
3078 	reflection_object *intern;
3079 	type_reference *param;
3080 
3081 	if (zend_parse_parameters_none() == FAILURE) {
3082 		RETURN_THROWS();
3083 	}
3084 	GET_REFLECTION_OBJECT_PTR(param);
3085 
3086 	RETURN_STR(zend_named_reflection_type_to_string(param->type));
3087 }
3088 /* }}} */
3089 
3090 /* {{{ Return the name of the type */
ZEND_METHOD(ReflectionNamedType,getName)3091 ZEND_METHOD(ReflectionNamedType, getName)
3092 {
3093 	reflection_object *intern;
3094 	type_reference *param;
3095 
3096 	if (zend_parse_parameters_none() == FAILURE) {
3097 		RETURN_THROWS();
3098 	}
3099 	GET_REFLECTION_OBJECT_PTR(param);
3100 
3101 	if (param->legacy_behavior) {
3102 		RETURN_STR(zend_type_to_string_without_null(param->type));
3103 	}
3104 	RETURN_STR(zend_named_reflection_type_to_string(param->type));
3105 }
3106 /* }}} */
3107 
3108 /* {{{ Returns whether type is a builtin type */
ZEND_METHOD(ReflectionNamedType,isBuiltin)3109 ZEND_METHOD(ReflectionNamedType, isBuiltin)
3110 {
3111 	reflection_object *intern;
3112 	type_reference *param;
3113 
3114 	if (zend_parse_parameters_none() == FAILURE) {
3115 		RETURN_THROWS();
3116 	}
3117 	GET_REFLECTION_OBJECT_PTR(param);
3118 
3119 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(param->type)) {
3120 		RETURN_TRUE;
3121 	}
3122 
3123 	/* Treat "static" as a class type for the purposes of reflection. */
3124 	RETVAL_BOOL(ZEND_TYPE_IS_ONLY_MASK(param->type)
3125 		&& !(ZEND_TYPE_FULL_MASK(param->type) & MAY_BE_STATIC));
3126 }
3127 /* }}} */
3128 
append_type(zval * return_value,zend_type type)3129 static void append_type(zval *return_value, zend_type type) {
3130 	zval reflection_type;
3131 	/* Drop iterable BC bit for type list */
3132 	if (ZEND_TYPE_IS_ITERABLE_FALLBACK(type)) {
3133 		ZEND_TYPE_FULL_MASK(type) &= ~_ZEND_TYPE_ITERABLE_BIT;
3134 	}
3135 
3136 	reflection_type_factory(type, &reflection_type, 0);
3137 	zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &reflection_type);
3138 }
3139 
append_type_mask(zval * return_value,uint32_t type_mask)3140 static void append_type_mask(zval *return_value, uint32_t type_mask) {
3141 	append_type(return_value, (zend_type) ZEND_TYPE_INIT_MASK(type_mask));
3142 }
3143 
3144 /* {{{ Returns the types that are part of this union type */
ZEND_METHOD(ReflectionUnionType,getTypes)3145 ZEND_METHOD(ReflectionUnionType, getTypes)
3146 {
3147 	reflection_object *intern;
3148 	type_reference *param;
3149 	uint32_t type_mask;
3150 
3151 	if (zend_parse_parameters_none() == FAILURE) {
3152 		RETURN_THROWS();
3153 	}
3154 	GET_REFLECTION_OBJECT_PTR(param);
3155 
3156 	array_init(return_value);
3157 	if (ZEND_TYPE_HAS_LIST(param->type)) {
3158 		zend_type *list_type;
3159 		ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
3160 			append_type(return_value, *list_type);
3161 		} ZEND_TYPE_LIST_FOREACH_END();
3162 	} else if (ZEND_TYPE_HAS_NAME(param->type)) {
3163 		zend_string *name = ZEND_TYPE_NAME(param->type);
3164 		append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, 0, 0));
3165 	}
3166 
3167 	type_mask = ZEND_TYPE_PURE_MASK(param->type);
3168 	ZEND_ASSERT(!(type_mask & MAY_BE_VOID));
3169 	ZEND_ASSERT(!(type_mask & MAY_BE_NEVER));
3170 	if (type_mask & MAY_BE_STATIC) {
3171 		append_type_mask(return_value, MAY_BE_STATIC);
3172 	}
3173 	if (type_mask & MAY_BE_CALLABLE) {
3174 		append_type_mask(return_value, MAY_BE_CALLABLE);
3175 	}
3176 	if (type_mask & MAY_BE_OBJECT) {
3177 		append_type_mask(return_value, MAY_BE_OBJECT);
3178 	}
3179 	if (type_mask & MAY_BE_ARRAY) {
3180 		append_type_mask(return_value, MAY_BE_ARRAY);
3181 	}
3182 	if (type_mask & MAY_BE_STRING) {
3183 		append_type_mask(return_value, MAY_BE_STRING);
3184 	}
3185 	if (type_mask & MAY_BE_LONG) {
3186 		append_type_mask(return_value, MAY_BE_LONG);
3187 	}
3188 	if (type_mask & MAY_BE_DOUBLE) {
3189 		append_type_mask(return_value, MAY_BE_DOUBLE);
3190 	}
3191 	if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
3192 		append_type_mask(return_value, MAY_BE_BOOL);
3193 	} else if (type_mask & MAY_BE_TRUE) {
3194 		append_type_mask(return_value, MAY_BE_TRUE);
3195 	} else if (type_mask & MAY_BE_FALSE) {
3196 		append_type_mask(return_value, MAY_BE_FALSE);
3197 	}
3198 	if (type_mask & MAY_BE_NULL) {
3199 		append_type_mask(return_value, MAY_BE_NULL);
3200 	}
3201 }
3202 /* }}} */
3203 
3204 /* {{{ Returns the types that are part of this intersection type */
ZEND_METHOD(ReflectionIntersectionType,getTypes)3205 ZEND_METHOD(ReflectionIntersectionType, getTypes)
3206 {
3207 	reflection_object *intern;
3208 	type_reference *param;
3209 	zend_type *list_type;
3210 
3211 	if (zend_parse_parameters_none() == FAILURE) {
3212 		RETURN_THROWS();
3213 	}
3214 	GET_REFLECTION_OBJECT_PTR(param);
3215 
3216 	ZEND_ASSERT(ZEND_TYPE_HAS_LIST(param->type));
3217 
3218 	array_init(return_value);
3219 	ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
3220 		append_type(return_value, *list_type);
3221 	} ZEND_TYPE_LIST_FOREACH_END();
3222 }
3223 /* }}} */
3224 
3225 /* {{{ Constructor. Throws an Exception in case the given method does not exist */
instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS,bool is_constructor)3226 static void instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
3227 {
3228 	zend_object *arg1_obj = NULL;
3229 	zend_string *arg1_str;
3230 	zend_string *arg2_str = NULL;
3231 
3232 	zend_object *orig_obj = NULL;
3233 	zend_class_entry *ce = NULL;
3234 	zend_string *class_name = NULL;
3235 	char *method_name;
3236 	size_t method_name_len;
3237 	char *lcname;
3238 
3239 	zval *object;
3240 	reflection_object *intern;
3241 	zend_function *mptr;
3242 
3243 	if (is_constructor) {
3244 		if (ZEND_NUM_ARGS() == 1) {
3245 			zend_error(E_DEPRECATED, "Calling ReflectionMethod::__construct() with 1 argument is deprecated, "
3246 				"use ReflectionMethod::createFromMethodName() instead");
3247 			if (UNEXPECTED(EG(exception))) {
3248 				RETURN_THROWS();
3249 			}
3250 		}
3251 
3252 		ZEND_PARSE_PARAMETERS_START(1, 2)
3253 			Z_PARAM_OBJ_OR_STR(arg1_obj, arg1_str)
3254 			Z_PARAM_OPTIONAL
3255 			Z_PARAM_STR_OR_NULL(arg2_str)
3256 		ZEND_PARSE_PARAMETERS_END();
3257 	} else {
3258 		ZEND_PARSE_PARAMETERS_START(1, 1)
3259 			Z_PARAM_STR(arg1_str)
3260 		ZEND_PARSE_PARAMETERS_END();
3261 	}
3262 
3263 	if (arg1_obj) {
3264 		if (!arg2_str) {
3265 			zend_argument_value_error(2, "cannot be null when argument #1 ($objectOrMethod) is an object");
3266 			RETURN_THROWS();
3267 		}
3268 
3269 		orig_obj = arg1_obj;
3270 		ce = arg1_obj->ce;
3271 		method_name = ZSTR_VAL(arg2_str);
3272 		method_name_len = ZSTR_LEN(arg2_str);
3273 	} else if (arg2_str) {
3274 		class_name = zend_string_copy(arg1_str);
3275 		method_name = ZSTR_VAL(arg2_str);
3276 		method_name_len = ZSTR_LEN(arg2_str);
3277 	} else {
3278 		char *tmp;
3279 		size_t tmp_len;
3280 		char *name = ZSTR_VAL(arg1_str);
3281 
3282 		if ((tmp = strstr(name, "::")) == NULL) {
3283 			zend_argument_error(reflection_exception_ptr, 1, "must be a valid method name");
3284 			RETURN_THROWS();
3285 		}
3286 		tmp_len = tmp - name;
3287 
3288 		class_name = zend_string_init(name, tmp_len, 0);
3289 		method_name = tmp + 2;
3290 		method_name_len = ZSTR_LEN(arg1_str) - tmp_len - 2;
3291 	}
3292 
3293 	if (class_name) {
3294 		if ((ce = zend_lookup_class(class_name)) == NULL) {
3295 			if (!EG(exception)) {
3296 				zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_name));
3297 			}
3298 			zend_string_release(class_name);
3299 			RETURN_THROWS();
3300 		}
3301 
3302 		zend_string_release(class_name);
3303 	}
3304 
3305 	if (is_constructor) {
3306 		object = ZEND_THIS;
3307 	} else {
3308 		object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : reflection_method_ptr);
3309 		object = return_value;
3310 	}
3311 	intern = Z_REFLECTION_P(object);
3312 
3313 	lcname = zend_str_tolower_dup(method_name, method_name_len);
3314 
3315 	if (ce == zend_ce_closure && orig_obj && (method_name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3316 		&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3317 		&& (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
3318 	{
3319 		/* do nothing, mptr already set */
3320 	} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
3321 		efree(lcname);
3322 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3323 			"Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
3324 		RETURN_THROWS();
3325 	}
3326 	efree(lcname);
3327 
3328 	ZVAL_STR_COPY(reflection_prop_name(object), mptr->common.function_name);
3329 	ZVAL_STR_COPY(reflection_prop_class(object), mptr->common.scope->name);
3330 	intern->ptr = mptr;
3331 	intern->ref_type = REF_TYPE_FUNCTION;
3332 	intern->ce = ce;
3333 }
3334 
3335 /* {{{ Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHOD(ReflectionMethod,__construct)3336 ZEND_METHOD(ReflectionMethod, __construct) {
3337 	instantiate_reflection_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
3338 }
3339 /* }}} */
3340 
ZEND_METHOD(ReflectionMethod,createFromMethodName)3341 ZEND_METHOD(ReflectionMethod, createFromMethodName) {
3342 	instantiate_reflection_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
3343 }
3344 
3345 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionMethod,__toString)3346 ZEND_METHOD(ReflectionMethod, __toString)
3347 {
3348 	reflection_object *intern;
3349 	zend_function *mptr;
3350 	smart_str str = {0};
3351 
3352 	if (zend_parse_parameters_none() == FAILURE) {
3353 		RETURN_THROWS();
3354 	}
3355 	GET_REFLECTION_OBJECT_PTR(mptr);
3356 	_function_string(&str, mptr, intern->ce, "");
3357 	RETURN_STR(smart_str_extract(&str));
3358 }
3359 /* }}} */
3360 
3361 /* {{{ Invokes the function */
ZEND_METHOD(ReflectionMethod,getClosure)3362 ZEND_METHOD(ReflectionMethod, getClosure)
3363 {
3364 	reflection_object *intern;
3365 	zval *obj = NULL;
3366 	zend_function *mptr;
3367 
3368 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &obj) == FAILURE) {
3369 		RETURN_THROWS();
3370 	}
3371 
3372 	GET_REFLECTION_OBJECT_PTR(mptr);
3373 
3374 	if (mptr->common.fn_flags & ZEND_ACC_STATIC)  {
3375 		zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
3376 	} else {
3377 		if (!obj) {
3378 			zend_argument_value_error(1, "cannot be null for non-static methods");
3379 			RETURN_THROWS();
3380 		}
3381 
3382 		if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope)) {
3383 			_DO_THROW("Given object is not an instance of the class this method was declared in");
3384 			RETURN_THROWS();
3385 		}
3386 
3387 		/* This is an original closure object and __invoke is to be called. */
3388 		if (Z_OBJCE_P(obj) == zend_ce_closure &&
3389 			(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
3390 		{
3391 			RETURN_OBJ_COPY(Z_OBJ_P(obj));
3392 		} else {
3393 			zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj);
3394 		}
3395 	}
3396 }
3397 /* }}} */
3398 
3399 /* {{{ reflection_method_invoke */
reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS,int variadic)3400 static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic)
3401 {
3402 	zval retval;
3403 	zval *params = NULL, *object;
3404 	HashTable *named_params = NULL;
3405 	reflection_object *intern;
3406 	zend_function *mptr, *callback;
3407 	uint32_t argc = 0;
3408 	zend_class_entry *obj_ce;
3409 
3410 	GET_REFLECTION_OBJECT_PTR(mptr);
3411 
3412 	if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
3413 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3414 			"Trying to invoke abstract method %s::%s()",
3415 			ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3416 		RETURN_THROWS();
3417 	}
3418 
3419 	if (variadic) {
3420 		ZEND_PARSE_PARAMETERS_START(1, -1)
3421 			Z_PARAM_OBJECT_OR_NULL(object)
3422 			Z_PARAM_VARIADIC_WITH_NAMED(params, argc, named_params)
3423 		ZEND_PARSE_PARAMETERS_END();
3424 	} else {
3425 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!h", &object, &named_params) == FAILURE) {
3426 			RETURN_THROWS();
3427 		}
3428 	}
3429 
3430 	/* In case this is a static method, we shouldn't pass an object_ptr
3431 	 * (which is used as calling context aka $this). We can thus ignore the
3432 	 * first parameter.
3433 	 *
3434 	 * Else, we verify that the given object is an instance of the class.
3435 	 */
3436 	if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
3437 		object = NULL;
3438 		obj_ce = mptr->common.scope;
3439 	} else {
3440 		if (!object) {
3441 			zend_throw_exception_ex(reflection_exception_ptr, 0,
3442 				"Trying to invoke non static method %s::%s() without an object",
3443 				ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3444 			RETURN_THROWS();
3445 		}
3446 
3447 		obj_ce = Z_OBJCE_P(object);
3448 
3449 		if (!instanceof_function(obj_ce, mptr->common.scope)) {
3450 			if (!variadic) {
3451 				efree(params);
3452 			}
3453 			_DO_THROW("Given object is not an instance of the class this method was declared in");
3454 			RETURN_THROWS();
3455 		}
3456 	}
3457 	/* Copy the zend_function when calling via handler (e.g. Closure::__invoke()) */
3458 	callback = _copy_function(mptr);
3459 	zend_call_known_function(callback, (object ? Z_OBJ_P(object) : NULL), intern->ce, &retval, argc, params, named_params);
3460 
3461 	if (Z_TYPE(retval) == IS_UNDEF && !EG(exception)) {
3462 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3463 			"Invocation of method %s::%s() failed", ZSTR_VAL(mptr->common.scope->name), ZSTR_VAL(mptr->common.function_name));
3464 		RETURN_THROWS();
3465 	}
3466 
3467 	if (Z_ISREF(retval)) {
3468 		zend_unwrap_reference(&retval);
3469 	}
3470 	ZVAL_COPY_VALUE(return_value, &retval);
3471 }
3472 /* }}} */
3473 
3474 /* {{{ Invokes the method. */
ZEND_METHOD(ReflectionMethod,invoke)3475 ZEND_METHOD(ReflectionMethod, invoke)
3476 {
3477 	reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3478 }
3479 /* }}} */
3480 
3481 /* {{{ Invokes the function and pass its arguments as array. */
ZEND_METHOD(ReflectionMethod,invokeArgs)3482 ZEND_METHOD(ReflectionMethod, invokeArgs)
3483 {
3484 	reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3485 }
3486 /* }}} */
3487 
3488 /* {{{ Returns whether this method is final */
ZEND_METHOD(ReflectionMethod,isFinal)3489 ZEND_METHOD(ReflectionMethod, isFinal)
3490 {
3491 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3492 }
3493 /* }}} */
3494 
3495 /* {{{ Returns whether this method is abstract */
ZEND_METHOD(ReflectionMethod,isAbstract)3496 ZEND_METHOD(ReflectionMethod, isAbstract)
3497 {
3498 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ABSTRACT);
3499 }
3500 /* }}} */
3501 
3502 /* {{{ Returns whether this method is public */
ZEND_METHOD(ReflectionMethod,isPublic)3503 ZEND_METHOD(ReflectionMethod, isPublic)
3504 {
3505 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3506 }
3507 /* }}} */
3508 
3509 /* {{{ Returns whether this method is private */
ZEND_METHOD(ReflectionMethod,isPrivate)3510 ZEND_METHOD(ReflectionMethod, isPrivate)
3511 {
3512 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3513 }
3514 /* }}} */
3515 
3516 /* {{{ Returns whether this method is protected */
ZEND_METHOD(ReflectionMethod,isProtected)3517 ZEND_METHOD(ReflectionMethod, isProtected)
3518 {
3519 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3520 }
3521 /* }}} */
3522 
3523 /* {{{ Returns whether this function is deprecated */
ZEND_METHOD(ReflectionFunctionAbstract,isDeprecated)3524 ZEND_METHOD(ReflectionFunctionAbstract, isDeprecated)
3525 {
3526 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_DEPRECATED);
3527 }
3528 /* }}} */
3529 
3530 /* {{{ Returns whether this function is a generator */
ZEND_METHOD(ReflectionFunctionAbstract,isGenerator)3531 ZEND_METHOD(ReflectionFunctionAbstract, isGenerator)
3532 {
3533 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_GENERATOR);
3534 }
3535 /* }}} */
3536 
3537 /* {{{ Returns whether this function is variadic */
ZEND_METHOD(ReflectionFunctionAbstract,isVariadic)3538 ZEND_METHOD(ReflectionFunctionAbstract, isVariadic)
3539 {
3540 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VARIADIC);
3541 }
3542 /* }}} */
3543 
3544 /* {{{ Returns whether this function is static */
ZEND_METHOD(ReflectionFunctionAbstract,isStatic)3545 ZEND_METHOD(ReflectionFunctionAbstract, isStatic)
3546 {
3547 	_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
3548 }
3549 /* }}} */
3550 
3551 /* {{{ Returns whether this function is defined in namespace */
ZEND_METHOD(ReflectionFunctionAbstract,inNamespace)3552 ZEND_METHOD(ReflectionFunctionAbstract, inNamespace)
3553 {
3554 	reflection_object *intern;
3555 	zend_function *fptr;
3556 
3557 	if (zend_parse_parameters_none() == FAILURE) {
3558 		RETURN_THROWS();
3559 	}
3560 
3561 	GET_REFLECTION_OBJECT_PTR(fptr);
3562 
3563 	zend_string *name = fptr->common.function_name;
3564 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3565 	RETURN_BOOL(backslash);
3566 }
3567 /* }}} */
3568 
3569 /* {{{ Returns the name of namespace where this function is defined */
ZEND_METHOD(ReflectionFunctionAbstract,getNamespaceName)3570 ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName)
3571 {
3572 	reflection_object *intern;
3573 	zend_function *fptr;
3574 
3575 	if (zend_parse_parameters_none() == FAILURE) {
3576 		RETURN_THROWS();
3577 	}
3578 
3579 	GET_REFLECTION_OBJECT_PTR(fptr);
3580 
3581 	zend_string *name = fptr->common.function_name;
3582 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3583 	if (backslash) {
3584 		RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
3585 	}
3586 	RETURN_EMPTY_STRING();
3587 }
3588 /* }}} */
3589 
3590 /* {{{ Returns the short name of the function (without namespace part) */
ZEND_METHOD(ReflectionFunctionAbstract,getShortName)3591 ZEND_METHOD(ReflectionFunctionAbstract, getShortName)
3592 {
3593 	reflection_object *intern;
3594 	zend_function *fptr;
3595 
3596 	if (zend_parse_parameters_none() == FAILURE) {
3597 		RETURN_THROWS();
3598 	}
3599 
3600 	GET_REFLECTION_OBJECT_PTR(fptr);
3601 
3602 	zend_string *name = fptr->common.function_name;
3603 	if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) {
3604 		const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3605 		if (backslash) {
3606 			RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
3607 		}
3608 	}
3609 
3610 	RETURN_STR_COPY(name);
3611 }
3612 /* }}} */
3613 
3614 /* {{{ Return whether the function has a return type */
ZEND_METHOD(ReflectionFunctionAbstract,hasReturnType)3615 ZEND_METHOD(ReflectionFunctionAbstract, hasReturnType)
3616 {
3617 	reflection_object *intern;
3618 	zend_function *fptr;
3619 
3620 	if (zend_parse_parameters_none() == FAILURE) {
3621 		RETURN_THROWS();
3622 	}
3623 
3624 	GET_REFLECTION_OBJECT_PTR(fptr);
3625 
3626 	RETVAL_BOOL((fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && !ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]));
3627 }
3628 /* }}} */
3629 
3630 /* {{{ Returns the return type associated with the function */
ZEND_METHOD(ReflectionFunctionAbstract,getReturnType)3631 ZEND_METHOD(ReflectionFunctionAbstract, getReturnType)
3632 {
3633 	reflection_object *intern;
3634 	zend_function *fptr;
3635 
3636 	if (zend_parse_parameters_none() == FAILURE) {
3637 		RETURN_THROWS();
3638 	}
3639 
3640 	GET_REFLECTION_OBJECT_PTR(fptr);
3641 
3642 	if (!(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])) {
3643 		RETURN_NULL();
3644 	}
3645 
3646 	reflection_type_factory(fptr->common.arg_info[-1].type, return_value, 1);
3647 }
3648 /* }}} */
3649 
3650 /* {{{ Return whether the function has a return type */
ZEND_METHOD(ReflectionFunctionAbstract,hasTentativeReturnType)3651 ZEND_METHOD(ReflectionFunctionAbstract, hasTentativeReturnType)
3652 {
3653 	reflection_object *intern;
3654 	zend_function *fptr;
3655 
3656 	if (zend_parse_parameters_none() == FAILURE) {
3657 		RETURN_THROWS();
3658 	}
3659 
3660 	GET_REFLECTION_OBJECT_PTR(fptr);
3661 
3662 	RETVAL_BOOL(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]));
3663 }
3664 /* }}} */
3665 
3666 /* {{{ Returns the return type associated with the function */
ZEND_METHOD(ReflectionFunctionAbstract,getTentativeReturnType)3667 ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType)
3668 {
3669 	reflection_object *intern;
3670 	zend_function *fptr;
3671 
3672 	if (zend_parse_parameters_none() == FAILURE) {
3673 		RETURN_THROWS();
3674 	}
3675 
3676 	GET_REFLECTION_OBJECT_PTR(fptr);
3677 
3678 	if (!(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || !ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])) {
3679 		RETURN_NULL();
3680 	}
3681 
3682 	reflection_type_factory(fptr->common.arg_info[-1].type, return_value, 1);
3683 }
3684 /* }}} */
3685 
3686 /* {{{ Returns whether this method is the constructor */
ZEND_METHOD(ReflectionMethod,isConstructor)3687 ZEND_METHOD(ReflectionMethod, isConstructor)
3688 {
3689 	reflection_object *intern;
3690 	zend_function *mptr;
3691 
3692 	if (zend_parse_parameters_none() == FAILURE) {
3693 		RETURN_THROWS();
3694 	}
3695 	GET_REFLECTION_OBJECT_PTR(mptr);
3696 	/* we need to check if the ctor is the ctor of the class level we we
3697 	 * looking at since we might be looking at an inherited old style ctor
3698 	 * defined in base class. */
3699 	RETURN_BOOL((mptr->common.fn_flags & ZEND_ACC_CTOR) && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope);
3700 }
3701 /* }}} */
3702 
3703 /* {{{ Returns whether this method is a destructor */
ZEND_METHOD(ReflectionMethod,isDestructor)3704 ZEND_METHOD(ReflectionMethod, isDestructor)
3705 {
3706 	reflection_object *intern;
3707 	zend_function *mptr;
3708 
3709 	if (zend_parse_parameters_none() == FAILURE) {
3710 		RETURN_THROWS();
3711 	}
3712 	GET_REFLECTION_OBJECT_PTR(mptr);
3713 	RETURN_BOOL(zend_string_equals_literal_ci(
3714 		mptr->common.function_name, ZEND_DESTRUCTOR_FUNC_NAME));
3715 }
3716 /* }}} */
3717 
3718 /* {{{ Returns a bitfield of the access modifiers for this method */
ZEND_METHOD(ReflectionMethod,getModifiers)3719 ZEND_METHOD(ReflectionMethod, getModifiers)
3720 {
3721 	reflection_object *intern;
3722 	zend_function *mptr;
3723 	uint32_t keep_flags = ZEND_ACC_PPP_MASK
3724 		| ZEND_ACC_STATIC | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL;
3725 
3726 	if (zend_parse_parameters_none() == FAILURE) {
3727 		RETURN_THROWS();
3728 	}
3729 	GET_REFLECTION_OBJECT_PTR(mptr);
3730 
3731 	RETURN_LONG((mptr->common.fn_flags & keep_flags));
3732 }
3733 /* }}} */
3734 
3735 /* {{{ Get the declaring class */
ZEND_METHOD(ReflectionMethod,getDeclaringClass)3736 ZEND_METHOD(ReflectionMethod, getDeclaringClass)
3737 {
3738 	reflection_object *intern;
3739 	zend_function *mptr;
3740 
3741 	if (zend_parse_parameters_none() == FAILURE) {
3742 		RETURN_THROWS();
3743 	}
3744 
3745 	GET_REFLECTION_OBJECT_PTR(mptr);
3746 
3747 	zend_reflection_class_factory(mptr->common.scope, return_value);
3748 }
3749 /* }}} */
3750 
3751 /* {{{ Returns whether a method has a prototype or not */
ZEND_METHOD(ReflectionMethod,hasPrototype)3752 ZEND_METHOD(ReflectionMethod, hasPrototype)
3753 {
3754     reflection_object *intern;
3755     zend_function *mptr;
3756 
3757     if (zend_parse_parameters_none() == FAILURE) {
3758         RETURN_THROWS();
3759     }
3760 
3761     GET_REFLECTION_OBJECT_PTR(mptr);
3762     RETURN_BOOL(mptr->common.prototype != NULL);
3763 }
3764 /* }}} */
3765 
3766 /* {{{ Get the prototype */
ZEND_METHOD(ReflectionMethod,getPrototype)3767 ZEND_METHOD(ReflectionMethod, getPrototype)
3768 {
3769 	reflection_object *intern;
3770 	zend_function *mptr;
3771 
3772 	if (zend_parse_parameters_none() == FAILURE) {
3773 		RETURN_THROWS();
3774 	}
3775 
3776 	GET_REFLECTION_OBJECT_PTR(mptr);
3777 
3778 	if (!mptr->common.prototype) {
3779 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3780 			"Method %s::%s does not have a prototype", ZSTR_VAL(intern->ce->name), ZSTR_VAL(mptr->common.function_name));
3781 		RETURN_THROWS();
3782 	}
3783 
3784 	reflection_method_factory(mptr->common.prototype->common.scope, mptr->common.prototype, NULL, return_value);
3785 }
3786 /* }}} */
3787 
3788 /* {{{ Sets whether non-public methods can be invoked */
ZEND_METHOD(ReflectionMethod,setAccessible)3789 ZEND_METHOD(ReflectionMethod, setAccessible)
3790 {
3791 	bool visible;
3792 
3793 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
3794 		RETURN_THROWS();
3795 	}
3796 }
3797 /* }}} */
3798 
3799 /* {{{ Constructor. Throws an Exception in case the given class constant does not exist */
ZEND_METHOD(ReflectionClassConstant,__construct)3800 ZEND_METHOD(ReflectionClassConstant, __construct)
3801 {
3802 	zval *object;
3803 	zend_string *classname_str;
3804 	zend_object *classname_obj;
3805 	zend_string *constname;
3806 	reflection_object *intern;
3807 	zend_class_entry *ce;
3808 	zend_class_constant *constant = NULL;
3809 
3810 	ZEND_PARSE_PARAMETERS_START(2, 2)
3811 		Z_PARAM_OBJ_OR_STR(classname_obj, classname_str)
3812 		Z_PARAM_STR(constname)
3813 	ZEND_PARSE_PARAMETERS_END();
3814 
3815 	if (classname_obj) {
3816 		ce = classname_obj->ce;
3817 	} else {
3818 		if ((ce = zend_lookup_class(classname_str)) == NULL) {
3819 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
3820 			RETURN_THROWS();
3821 		}
3822 	}
3823 
3824 	object = ZEND_THIS;
3825 	intern = Z_REFLECTION_P(object);
3826 
3827 	if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
3828 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(constname));
3829 		RETURN_THROWS();
3830 	}
3831 
3832 	intern->ptr = constant;
3833 	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
3834 	intern->ce = constant->ce;
3835 	ZVAL_STR_COPY(reflection_prop_name(object), constname);
3836 	ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
3837 }
3838 /* }}} */
3839 
3840 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionClassConstant,__toString)3841 ZEND_METHOD(ReflectionClassConstant, __toString)
3842 {
3843 	reflection_object *intern;
3844 	zend_class_constant *ref;
3845 	smart_str str = {0};
3846 
3847 	if (zend_parse_parameters_none() == FAILURE) {
3848 		RETURN_THROWS();
3849 	}
3850 
3851 	GET_REFLECTION_OBJECT_PTR(ref);
3852 
3853 	zval *name = reflection_prop_name(ZEND_THIS);
3854 	if (Z_ISUNDEF_P(name)) {
3855 		zend_throw_error(NULL,
3856 			"Typed property ReflectionClassConstant::$name "
3857 			"must not be accessed before initialization");
3858 		RETURN_THROWS();
3859 	}
3860 	ZVAL_DEREF(name);
3861 	ZEND_ASSERT(Z_TYPE_P(name) == IS_STRING);
3862 
3863 	_class_const_string(&str, Z_STR_P(name), ref, "");
3864 	RETURN_STR(smart_str_extract(&str));
3865 }
3866 /* }}} */
3867 
3868 /* {{{ Returns the constant' name */
ZEND_METHOD(ReflectionClassConstant,getName)3869 ZEND_METHOD(ReflectionClassConstant, getName)
3870 {
3871 	if (zend_parse_parameters_none() == FAILURE) {
3872 		RETURN_THROWS();
3873 	}
3874 
3875 	zval *name = reflection_prop_name(ZEND_THIS);
3876 	if (Z_ISUNDEF_P(name)) {
3877 		zend_throw_error(NULL,
3878 			"Typed property ReflectionClassConstant::$name "
3879 			"must not be accessed before initialization");
3880 		RETURN_THROWS();
3881 	}
3882 
3883 	RETURN_COPY_DEREF(name);
3884 }
3885 /* }}} */
3886 
3887 /* Returns the type associated with the class constant */
ZEND_METHOD(ReflectionClassConstant,getType)3888 ZEND_METHOD(ReflectionClassConstant, getType)
3889 {
3890 	reflection_object *intern;
3891 	zend_class_constant *ref;
3892 
3893 	if (zend_parse_parameters_none() == FAILURE) {
3894 		RETURN_THROWS();
3895 	}
3896 
3897 	GET_REFLECTION_OBJECT_PTR(ref);
3898 
3899 	if (!ZEND_TYPE_IS_SET(ref->type)) {
3900 		RETURN_NULL();
3901 	}
3902 
3903 	reflection_type_factory(ref->type, return_value, 1);
3904 }
3905 
3906 /* Returns whether class constant has a type */
ZEND_METHOD(ReflectionClassConstant,hasType)3907 ZEND_METHOD(ReflectionClassConstant, hasType)
3908 {
3909 	reflection_object *intern;
3910 	zend_class_constant *ref;
3911 
3912 	if (zend_parse_parameters_none() == FAILURE) {
3913 		RETURN_THROWS();
3914 	}
3915 
3916 	GET_REFLECTION_OBJECT_PTR(ref);
3917 	RETVAL_BOOL(ZEND_TYPE_IS_SET(ref->type));
3918 }
3919 
_class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)3920 static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
3921 {
3922 	reflection_object *intern;
3923 	zend_class_constant *ref;
3924 
3925 	if (zend_parse_parameters_none() == FAILURE) {
3926 		RETURN_THROWS();
3927 	}
3928 	GET_REFLECTION_OBJECT_PTR(ref);
3929 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(ref) & mask);
3930 }
3931 /* }}} */
3932 
3933 /* {{{ Returns whether this constant is public */
ZEND_METHOD(ReflectionClassConstant,isPublic)3934 ZEND_METHOD(ReflectionClassConstant, isPublic)
3935 {
3936 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3937 }
3938 /* }}} */
3939 
3940 /* {{{ Returns whether this constant is private */
ZEND_METHOD(ReflectionClassConstant,isPrivate)3941 ZEND_METHOD(ReflectionClassConstant, isPrivate)
3942 {
3943 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3944 }
3945 /* }}} */
3946 
3947 /* {{{ Returns whether this constant is protected */
ZEND_METHOD(ReflectionClassConstant,isProtected)3948 ZEND_METHOD(ReflectionClassConstant, isProtected)
3949 {
3950 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3951 }
3952 /* }}} */
3953 
3954 /* Returns whether this constant is final */
ZEND_METHOD(ReflectionClassConstant,isFinal)3955 ZEND_METHOD(ReflectionClassConstant, isFinal)
3956 {
3957 	_class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3958 }
3959 
3960 /* {{{ Returns a bitfield of the access modifiers for this constant */
ZEND_METHOD(ReflectionClassConstant,getModifiers)3961 ZEND_METHOD(ReflectionClassConstant, getModifiers)
3962 {
3963 	reflection_object *intern;
3964 	zend_class_constant *ref;
3965 	uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_PPP_MASK;
3966 
3967 	if (zend_parse_parameters_none() == FAILURE) {
3968 		RETURN_THROWS();
3969 	}
3970 	GET_REFLECTION_OBJECT_PTR(ref);
3971 
3972 	RETURN_LONG(ZEND_CLASS_CONST_FLAGS(ref) & keep_flags);
3973 }
3974 /* }}} */
3975 
3976 /* {{{ Returns this constant's value */
ZEND_METHOD(ReflectionClassConstant,getValue)3977 ZEND_METHOD(ReflectionClassConstant, getValue)
3978 {
3979 	reflection_object *intern;
3980 	zend_class_constant *ref;
3981 
3982 	if (zend_parse_parameters_none() == FAILURE) {
3983 		RETURN_THROWS();
3984 	}
3985 	GET_REFLECTION_OBJECT_PTR(ref);
3986 
3987 	zval *name = reflection_prop_name(ZEND_THIS);
3988 	if (Z_ISUNDEF_P(name)) {
3989 		zend_throw_error(NULL,
3990 			"Typed property ReflectionClassConstant::$name "
3991 			"must not be accessed before initialization");
3992 		RETURN_THROWS();
3993 	}
3994 
3995 	if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
3996 		zend_result result = zend_update_class_constant(ref, Z_STR_P(name), ref->ce);
3997 		if (result == FAILURE) {
3998 			RETURN_THROWS();
3999 		}
4000 	}
4001 	ZVAL_COPY_OR_DUP(return_value, &ref->value);
4002 }
4003 /* }}} */
4004 
4005 /* {{{ Get the declaring class */
ZEND_METHOD(ReflectionClassConstant,getDeclaringClass)4006 ZEND_METHOD(ReflectionClassConstant, getDeclaringClass)
4007 {
4008 	reflection_object *intern;
4009 	zend_class_constant *ref;
4010 
4011 	if (zend_parse_parameters_none() == FAILURE) {
4012 		RETURN_THROWS();
4013 	}
4014 	GET_REFLECTION_OBJECT_PTR(ref);
4015 
4016 	zend_reflection_class_factory(ref->ce, return_value);
4017 }
4018 /* }}} */
4019 
4020 /* {{{ Returns the doc comment for this constant */
ZEND_METHOD(ReflectionClassConstant,getDocComment)4021 ZEND_METHOD(ReflectionClassConstant, getDocComment)
4022 {
4023 	reflection_object *intern;
4024 	zend_class_constant *ref;
4025 
4026 	if (zend_parse_parameters_none() == FAILURE) {
4027 		RETURN_THROWS();
4028 	}
4029 	GET_REFLECTION_OBJECT_PTR(ref);
4030 	if (ref->doc_comment) {
4031 		RETURN_STR_COPY(ref->doc_comment);
4032 	}
4033 	RETURN_FALSE;
4034 }
4035 /* }}} */
4036 
4037 /* {{{ Returns the attributes of this constant */
ZEND_METHOD(ReflectionClassConstant,getAttributes)4038 ZEND_METHOD(ReflectionClassConstant, getAttributes)
4039 {
4040 	reflection_object *intern;
4041 	zend_class_constant *ref;
4042 
4043 	GET_REFLECTION_OBJECT_PTR(ref);
4044 
4045 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
4046 		ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST,
4047 		ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL);
4048 }
4049 /* }}} */
4050 
ZEND_METHOD(ReflectionClassConstant,isEnumCase)4051 ZEND_METHOD(ReflectionClassConstant, isEnumCase)
4052 {
4053 	reflection_object *intern;
4054 	zend_class_constant *ref;
4055 
4056 	GET_REFLECTION_OBJECT_PTR(ref);
4057 
4058 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(ref) & ZEND_CLASS_CONST_IS_CASE);
4059 }
4060 
ZEND_METHOD(ReflectionClassConstant,isDeprecated)4061 ZEND_METHOD(ReflectionClassConstant, isDeprecated)
4062 {
4063 	reflection_object *intern;
4064 	zend_constant *ref;
4065 
4066 	if (zend_parse_parameters_none() == FAILURE) {
4067 		RETURN_THROWS();
4068 	}
4069 
4070 	GET_REFLECTION_OBJECT_PTR(ref);
4071 
4072 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(ref) & ZEND_ACC_DEPRECATED);
4073 }
4074 
4075 /* {{{ reflection_class_object_ctor */
reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS,int is_object)4076 static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_object)
4077 {
4078 	zval *object;
4079 	zend_string *arg_class = NULL;
4080 	zend_object *arg_obj;
4081 	reflection_object *intern;
4082 	zend_class_entry *ce;
4083 
4084 	if (is_object) {
4085 		ZEND_PARSE_PARAMETERS_START(1, 1)
4086 			Z_PARAM_OBJ(arg_obj)
4087 		ZEND_PARSE_PARAMETERS_END();
4088 	} else {
4089 		ZEND_PARSE_PARAMETERS_START(1, 1)
4090 			Z_PARAM_OBJ_OR_STR(arg_obj, arg_class)
4091 		ZEND_PARSE_PARAMETERS_END();
4092 	}
4093 
4094 	object = ZEND_THIS;
4095 	intern = Z_REFLECTION_P(object);
4096 
4097 	if (arg_obj) {
4098 		ZVAL_STR_COPY(reflection_prop_name(object), arg_obj->ce->name);
4099 		intern->ptr = arg_obj->ce;
4100 		if (is_object) {
4101 			ZVAL_OBJ_COPY(&intern->obj, arg_obj);
4102 		}
4103 	} else {
4104 		if ((ce = zend_lookup_class(arg_class)) == NULL) {
4105 			if (!EG(exception)) {
4106 				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(arg_class));
4107 			}
4108 			RETURN_THROWS();
4109 		}
4110 
4111 		ZVAL_STR_COPY(reflection_prop_name(object), ce->name);
4112 		intern->ptr = ce;
4113 	}
4114 	intern->ref_type = REF_TYPE_OTHER;
4115 }
4116 /* }}} */
4117 
4118 /* {{{ Constructor. Takes a string or an instance as an argument */
ZEND_METHOD(ReflectionClass,__construct)4119 ZEND_METHOD(ReflectionClass, __construct)
4120 {
4121 	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4122 }
4123 /* }}} */
4124 
4125 /* {{{ add_class_vars */
add_class_vars(zend_class_entry * ce,bool statics,zval * return_value)4126 static void add_class_vars(zend_class_entry *ce, bool statics, zval *return_value)
4127 {
4128 	zend_property_info *prop_info;
4129 	zval *prop, prop_copy;
4130 	zend_string *key;
4131 
4132 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
4133 		if (((prop_info->flags & ZEND_ACC_PRIVATE) &&
4134 		     prop_info->ce != ce)) {
4135 			continue;
4136 		}
4137 
4138 		bool is_static = (prop_info->flags & ZEND_ACC_STATIC) != 0;
4139 		if (statics != is_static) {
4140 			continue;
4141 		}
4142 
4143 		prop = property_get_default(prop_info);
4144 		if (Z_ISUNDEF_P(prop)) {
4145 			continue;
4146 		}
4147 
4148 		/* copy: enforce read only access */
4149 		ZVAL_DEREF(prop);
4150 		ZVAL_COPY_OR_DUP(&prop_copy, prop);
4151 
4152 		/* this is necessary to make it able to work with default array
4153 		* properties, returned to user */
4154 		if (Z_TYPE(prop_copy) == IS_CONSTANT_AST) {
4155 			if (UNEXPECTED(zval_update_constant_ex(&prop_copy, ce) != SUCCESS)) {
4156 				return;
4157 			}
4158 		}
4159 
4160 		zend_hash_update(Z_ARRVAL_P(return_value), key, &prop_copy);
4161 	} ZEND_HASH_FOREACH_END();
4162 }
4163 /* }}} */
4164 
4165 /* {{{ Returns an associative array containing all static property values of the class */
ZEND_METHOD(ReflectionClass,getStaticProperties)4166 ZEND_METHOD(ReflectionClass, getStaticProperties)
4167 {
4168 	reflection_object *intern;
4169 	zend_class_entry *ce;
4170 	zend_property_info *prop_info;
4171 	zval *prop;
4172 	zend_string *key;
4173 
4174 	if (zend_parse_parameters_none() == FAILURE) {
4175 		RETURN_THROWS();
4176 	}
4177 
4178 	GET_REFLECTION_OBJECT_PTR(ce);
4179 
4180 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4181 		RETURN_THROWS();
4182 	}
4183 
4184 	if (ce->default_static_members_count && !CE_STATIC_MEMBERS(ce)) {
4185 		zend_class_init_statics(ce);
4186 	}
4187 
4188 	array_init(return_value);
4189 
4190 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
4191 		if (((prop_info->flags & ZEND_ACC_PRIVATE) &&
4192 		     prop_info->ce != ce)) {
4193 			continue;
4194 		}
4195 		if ((prop_info->flags & ZEND_ACC_STATIC) == 0) {
4196 			continue;
4197 		}
4198 
4199 		prop = &CE_STATIC_MEMBERS(ce)[prop_info->offset];
4200 		ZVAL_DEINDIRECT(prop);
4201 
4202 		if (ZEND_TYPE_IS_SET(prop_info->type) && Z_ISUNDEF_P(prop)) {
4203 			continue;
4204 		}
4205 
4206 		/* enforce read only access */
4207 		ZVAL_DEREF(prop);
4208 		Z_TRY_ADDREF_P(prop);
4209 
4210 		zend_hash_update(Z_ARRVAL_P(return_value), key, prop);
4211 	} ZEND_HASH_FOREACH_END();
4212 }
4213 /* }}} */
4214 
4215 /* {{{ Returns the value of a static property */
ZEND_METHOD(ReflectionClass,getStaticPropertyValue)4216 ZEND_METHOD(ReflectionClass, getStaticPropertyValue)
4217 {
4218 	reflection_object *intern;
4219 	zend_class_entry *ce, *old_scope;
4220 	zend_string *name;
4221 	zval *prop, *def_value = NULL;
4222 
4223 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &name, &def_value) == FAILURE) {
4224 		RETURN_THROWS();
4225 	}
4226 
4227 	GET_REFLECTION_OBJECT_PTR(ce);
4228 
4229 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4230 		RETURN_THROWS();
4231 	}
4232 
4233 	old_scope = EG(fake_scope);
4234 	EG(fake_scope) = ce;
4235 	prop = zend_std_get_static_property(ce, name, BP_VAR_IS);
4236 	EG(fake_scope) = old_scope;
4237 
4238 	if (prop) {
4239 		RETURN_COPY_DEREF(prop);
4240 	}
4241 
4242 	if (def_value) {
4243 		RETURN_COPY(def_value);
4244 	}
4245 
4246 	zend_throw_exception_ex(reflection_exception_ptr, 0,
4247 		"Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4248 }
4249 /* }}} */
4250 
4251 /* {{{ Sets the value of a static property */
ZEND_METHOD(ReflectionClass,setStaticPropertyValue)4252 ZEND_METHOD(ReflectionClass, setStaticPropertyValue)
4253 {
4254 	reflection_object *intern;
4255 	zend_class_entry *ce, *old_scope;
4256 	zend_property_info *prop_info;
4257 	zend_string *name;
4258 	zval *variable_ptr, *value;
4259 
4260 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &name, &value) == FAILURE) {
4261 		RETURN_THROWS();
4262 	}
4263 
4264 	GET_REFLECTION_OBJECT_PTR(ce);
4265 
4266 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4267 		RETURN_THROWS();
4268 	}
4269 	old_scope = EG(fake_scope);
4270 	EG(fake_scope) = ce;
4271 	variable_ptr =  zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info);
4272 	EG(fake_scope) = old_scope;
4273 	if (!variable_ptr) {
4274 		zend_clear_exception();
4275 		zend_throw_exception_ex(reflection_exception_ptr, 0,
4276 				"Class %s does not have a property named %s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4277 		RETURN_THROWS();
4278 	}
4279 
4280 	if (Z_ISREF_P(variable_ptr)) {
4281 		zend_reference *ref = Z_REF_P(variable_ptr);
4282 		variable_ptr = Z_REFVAL_P(variable_ptr);
4283 
4284 		if (!zend_verify_ref_assignable_zval(ref, value, 0)) {
4285 			return;
4286 		}
4287 	}
4288 
4289 	if (ZEND_TYPE_IS_SET(prop_info->type) && !zend_verify_property_type(prop_info, value, 0)) {
4290 		return;
4291 	}
4292 
4293 	zval_ptr_dtor(variable_ptr);
4294 	ZVAL_COPY(variable_ptr, value);
4295 
4296 }
4297 /* }}} */
4298 
4299 /* {{{ Returns an associative array containing copies of all default property values of the class */
ZEND_METHOD(ReflectionClass,getDefaultProperties)4300 ZEND_METHOD(ReflectionClass, getDefaultProperties)
4301 {
4302 	reflection_object *intern;
4303 	zend_class_entry *ce;
4304 
4305 	if (zend_parse_parameters_none() == FAILURE) {
4306 		RETURN_THROWS();
4307 	}
4308 	GET_REFLECTION_OBJECT_PTR(ce);
4309 	array_init(return_value);
4310 	if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4311 		RETURN_THROWS();
4312 	}
4313 	add_class_vars(ce, 1, return_value);
4314 	add_class_vars(ce, 0, return_value);
4315 }
4316 /* }}} */
4317 
4318 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionClass,__toString)4319 ZEND_METHOD(ReflectionClass, __toString)
4320 {
4321 	reflection_object *intern;
4322 	zend_class_entry *ce;
4323 	smart_str str = {0};
4324 
4325 	if (zend_parse_parameters_none() == FAILURE) {
4326 		RETURN_THROWS();
4327 	}
4328 	GET_REFLECTION_OBJECT_PTR(ce);
4329 	_class_string(&str, ce, &intern->obj, "");
4330 	RETURN_STR(smart_str_extract(&str));
4331 }
4332 /* }}} */
4333 
4334 /* {{{ Returns the class' name */
ZEND_METHOD(ReflectionClass,getName)4335 ZEND_METHOD(ReflectionClass, getName)
4336 {
4337 	reflection_object *intern;
4338 	zend_class_entry *ce;
4339 
4340 	if (zend_parse_parameters_none() == FAILURE) {
4341 		RETURN_THROWS();
4342 	}
4343 
4344 	GET_REFLECTION_OBJECT_PTR(ce);
4345 	RETURN_STR_COPY(ce->name);
4346 }
4347 /* }}} */
4348 
4349 /* {{{ Returns whether this class is an internal class */
ZEND_METHOD(ReflectionClass,isInternal)4350 ZEND_METHOD(ReflectionClass, isInternal)
4351 {
4352 	reflection_object *intern;
4353 	zend_class_entry *ce;
4354 
4355 	if (zend_parse_parameters_none() == FAILURE) {
4356 		RETURN_THROWS();
4357 	}
4358 	GET_REFLECTION_OBJECT_PTR(ce);
4359 	RETURN_BOOL(ce->type == ZEND_INTERNAL_CLASS);
4360 }
4361 /* }}} */
4362 
4363 /* {{{ Returns whether this class is user-defined */
ZEND_METHOD(ReflectionClass,isUserDefined)4364 ZEND_METHOD(ReflectionClass, isUserDefined)
4365 {
4366 	reflection_object *intern;
4367 	zend_class_entry *ce;
4368 
4369 	if (zend_parse_parameters_none() == FAILURE) {
4370 		RETURN_THROWS();
4371 	}
4372 	GET_REFLECTION_OBJECT_PTR(ce);
4373 	RETURN_BOOL(ce->type == ZEND_USER_CLASS);
4374 }
4375 /* }}} */
4376 
4377 /* {{{ Returns whether this class is anonymous */
ZEND_METHOD(ReflectionClass,isAnonymous)4378 ZEND_METHOD(ReflectionClass, isAnonymous)
4379 {
4380 	reflection_object *intern;
4381 	zend_class_entry *ce;
4382 
4383 	if (zend_parse_parameters_none() == FAILURE) {
4384 		RETURN_THROWS();
4385 	}
4386 	GET_REFLECTION_OBJECT_PTR(ce);
4387 	RETURN_BOOL(ce->ce_flags & ZEND_ACC_ANON_CLASS);
4388 }
4389 /* }}} */
4390 
4391 /* {{{ Returns the filename of the file this class was declared in */
ZEND_METHOD(ReflectionClass,getFileName)4392 ZEND_METHOD(ReflectionClass, getFileName)
4393 {
4394 	reflection_object *intern;
4395 	zend_class_entry *ce;
4396 
4397 	if (zend_parse_parameters_none() == FAILURE) {
4398 		RETURN_THROWS();
4399 	}
4400 	GET_REFLECTION_OBJECT_PTR(ce);
4401 	if (ce->type == ZEND_USER_CLASS) {
4402 		RETURN_STR_COPY(ce->info.user.filename);
4403 	}
4404 	RETURN_FALSE;
4405 }
4406 /* }}} */
4407 
4408 /* {{{ Returns the line this class' declaration starts at */
ZEND_METHOD(ReflectionClass,getStartLine)4409 ZEND_METHOD(ReflectionClass, getStartLine)
4410 {
4411 	reflection_object *intern;
4412 	zend_class_entry *ce;
4413 
4414 	if (zend_parse_parameters_none() == FAILURE) {
4415 		RETURN_THROWS();
4416 	}
4417 	GET_REFLECTION_OBJECT_PTR(ce);
4418 	if (ce->type == ZEND_USER_CLASS) {
4419 		RETURN_LONG(ce->info.user.line_start);
4420 	}
4421 	RETURN_FALSE;
4422 }
4423 /* }}} */
4424 
4425 /* {{{ Returns the line this class' declaration ends at */
ZEND_METHOD(ReflectionClass,getEndLine)4426 ZEND_METHOD(ReflectionClass, getEndLine)
4427 {
4428 	reflection_object *intern;
4429 	zend_class_entry *ce;
4430 
4431 	if (zend_parse_parameters_none() == FAILURE) {
4432 		RETURN_THROWS();
4433 	}
4434 	GET_REFLECTION_OBJECT_PTR(ce);
4435 	if (ce->type == ZEND_USER_CLASS) {
4436 		RETURN_LONG(ce->info.user.line_end);
4437 	}
4438 	RETURN_FALSE;
4439 }
4440 /* }}} */
4441 
4442 /* {{{ Returns the doc comment for this class */
ZEND_METHOD(ReflectionClass,getDocComment)4443 ZEND_METHOD(ReflectionClass, getDocComment)
4444 {
4445 	reflection_object *intern;
4446 	zend_class_entry *ce;
4447 
4448 	if (zend_parse_parameters_none() == FAILURE) {
4449 		RETURN_THROWS();
4450 	}
4451 	GET_REFLECTION_OBJECT_PTR(ce);
4452 	if (ce->doc_comment) {
4453 		RETURN_STR_COPY(ce->doc_comment);
4454 	}
4455 	RETURN_FALSE;
4456 }
4457 /* }}} */
4458 
4459 /* {{{ Returns the attributes for this class */
ZEND_METHOD(ReflectionClass,getAttributes)4460 ZEND_METHOD(ReflectionClass, getAttributes)
4461 {
4462 	reflection_object *intern;
4463 	zend_class_entry *ce;
4464 
4465 	GET_REFLECTION_OBJECT_PTR(ce);
4466 
4467 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
4468 		ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS,
4469 		ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL);
4470 }
4471 /* }}} */
4472 
4473 /* {{{ Returns the class' constructor if there is one, NULL otherwise */
ZEND_METHOD(ReflectionClass,getConstructor)4474 ZEND_METHOD(ReflectionClass, getConstructor)
4475 {
4476 	reflection_object *intern;
4477 	zend_class_entry *ce;
4478 
4479 	if (zend_parse_parameters_none() == FAILURE) {
4480 		RETURN_THROWS();
4481 	}
4482 	GET_REFLECTION_OBJECT_PTR(ce);
4483 
4484 	if (ce->constructor) {
4485 		reflection_method_factory(ce, ce->constructor, NULL, return_value);
4486 	} else {
4487 		RETURN_NULL();
4488 	}
4489 }
4490 /* }}} */
4491 
4492 /* {{{ Returns whether a method exists or not */
ZEND_METHOD(ReflectionClass,hasMethod)4493 ZEND_METHOD(ReflectionClass, hasMethod)
4494 {
4495 	reflection_object *intern;
4496 	zend_class_entry *ce;
4497 	zend_string *name, *lc_name;
4498 
4499 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4500 		RETURN_THROWS();
4501 	}
4502 
4503 	GET_REFLECTION_OBJECT_PTR(ce);
4504 	lc_name = zend_string_tolower(name);
4505 	RETVAL_BOOL(zend_hash_exists(&ce->function_table, lc_name) || is_closure_invoke(ce, lc_name));
4506 	zend_string_release(lc_name);
4507 }
4508 /* }}} */
4509 
4510 /* {{{ Returns the class' method specified by its name */
ZEND_METHOD(ReflectionClass,getMethod)4511 ZEND_METHOD(ReflectionClass, getMethod)
4512 {
4513 	reflection_object *intern;
4514 	zend_class_entry *ce;
4515 	zend_function *mptr;
4516 	zval obj_tmp;
4517 	zend_string *name, *lc_name;
4518 
4519 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4520 		RETURN_THROWS();
4521 	}
4522 
4523 	GET_REFLECTION_OBJECT_PTR(ce);
4524 	lc_name = zend_string_tolower(name);
4525 	if (!Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name)
4526 		&& (mptr = zend_get_closure_invoke_method(Z_OBJ(intern->obj))) != NULL)
4527 	{
4528 		/* don't assign closure_object since we only reflect the invoke handler
4529 		   method and not the closure definition itself */
4530 		reflection_method_factory(ce, mptr, NULL, return_value);
4531 	} else if (Z_ISUNDEF(intern->obj) && is_closure_invoke(ce, lc_name)
4532 		&& object_init_ex(&obj_tmp, ce) == SUCCESS && (mptr = zend_get_closure_invoke_method(Z_OBJ(obj_tmp))) != NULL) {
4533 		/* don't assign closure_object since we only reflect the invoke handler
4534 		   method and not the closure definition itself */
4535 		reflection_method_factory(ce, mptr, NULL, return_value);
4536 		zval_ptr_dtor(&obj_tmp);
4537 	} else if ((mptr = zend_hash_find_ptr(&ce->function_table, lc_name)) != NULL) {
4538 		reflection_method_factory(ce, mptr, NULL, return_value);
4539 	} else {
4540 		zend_throw_exception_ex(reflection_exception_ptr, 0,
4541 				"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4542 	}
4543 	zend_string_release(lc_name);
4544 }
4545 /* }}} */
4546 
4547 /* {{{ _addmethod */
_addmethod(zend_function * mptr,zend_class_entry * ce,HashTable * ht,zend_long filter)4548 static bool _addmethod(zend_function *mptr, zend_class_entry *ce, HashTable *ht, zend_long filter)
4549 {
4550 	if ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) && mptr->common.scope != ce) {
4551 		return 0;
4552 	}
4553 
4554 	if (mptr->common.fn_flags & filter) {
4555 		zval method;
4556 		reflection_method_factory(ce, mptr, NULL, &method);
4557 		zend_hash_next_index_insert_new(ht, &method);
4558 		return 1;
4559 	}
4560 	return 0;
4561 }
4562 /* }}} */
4563 
4564 /* {{{ Returns an array of this class' methods */
ZEND_METHOD(ReflectionClass,getMethods)4565 ZEND_METHOD(ReflectionClass, getMethods)
4566 {
4567 	reflection_object *intern;
4568 	zend_class_entry *ce;
4569 	zend_function *mptr;
4570 	zend_long filter;
4571 	bool filter_is_null = 1;
4572 
4573 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4574 		RETURN_THROWS();
4575 	}
4576 
4577 	if (filter_is_null) {
4578 		filter = ZEND_ACC_PPP_MASK | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL | ZEND_ACC_STATIC;
4579 	}
4580 
4581 	GET_REFLECTION_OBJECT_PTR(ce);
4582 
4583 	array_init(return_value);
4584 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
4585 		_addmethod(mptr, ce, Z_ARRVAL_P(return_value), filter);
4586 	} ZEND_HASH_FOREACH_END();
4587 
4588 	if (instanceof_function(ce, zend_ce_closure)) {
4589 		bool has_obj = Z_TYPE(intern->obj) != IS_UNDEF;
4590 		zval obj_tmp;
4591 		zend_object *obj;
4592 		if (!has_obj) {
4593 			object_init_ex(&obj_tmp, ce);
4594 			obj = Z_OBJ(obj_tmp);
4595 		} else {
4596 			obj = Z_OBJ(intern->obj);
4597 		}
4598 		zend_function *closure = zend_get_closure_invoke_method(obj);
4599 		if (closure) {
4600 			if (!_addmethod(closure, ce, Z_ARRVAL_P(return_value), filter)) {
4601 				_free_function(closure);
4602 			}
4603 		}
4604 		if (!has_obj) {
4605 			zval_ptr_dtor(&obj_tmp);
4606 		}
4607 	}
4608 }
4609 /* }}} */
4610 
4611 /* {{{ Returns whether a property exists or not */
ZEND_METHOD(ReflectionClass,hasProperty)4612 ZEND_METHOD(ReflectionClass, hasProperty)
4613 {
4614 	reflection_object *intern;
4615 	zend_property_info *property_info;
4616 	zend_class_entry *ce;
4617 	zend_string *name;
4618 
4619 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4620 		RETURN_THROWS();
4621 	}
4622 
4623 	GET_REFLECTION_OBJECT_PTR(ce);
4624 	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
4625 		if ((property_info->flags & ZEND_ACC_PRIVATE) && property_info->ce != ce) {
4626 			RETURN_FALSE;
4627 		}
4628 		RETURN_TRUE;
4629 	} else {
4630 		if (Z_TYPE(intern->obj) != IS_UNDEF) {
4631 			if (Z_OBJ_HANDLER(intern->obj, has_property)(Z_OBJ(intern->obj), name, 2, NULL)) {
4632 				RETURN_TRUE;
4633 			}
4634 		}
4635 		RETURN_FALSE;
4636 	}
4637 }
4638 /* }}} */
4639 
4640 /* {{{ Returns the class' property specified by its name */
ZEND_METHOD(ReflectionClass,getProperty)4641 ZEND_METHOD(ReflectionClass, getProperty)
4642 {
4643 	reflection_object *intern;
4644 	zend_class_entry *ce, *ce2;
4645 	zend_property_info *property_info;
4646 	zend_string *name, *classname;
4647 	char *tmp, *str_name;
4648 	size_t classname_len, str_name_len;
4649 
4650 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4651 		RETURN_THROWS();
4652 	}
4653 
4654 	GET_REFLECTION_OBJECT_PTR(ce);
4655 	if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL) {
4656 		if (!(property_info->flags & ZEND_ACC_PRIVATE) || property_info->ce == ce) {
4657 			reflection_property_factory(ce, name, property_info, return_value);
4658 			return;
4659 		}
4660 	} else if (Z_TYPE(intern->obj) != IS_UNDEF) {
4661 		/* Check for dynamic properties */
4662 		if (zend_hash_exists(Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj)), name)) {
4663 			reflection_property_factory(ce, name, NULL, return_value);
4664 			return;
4665 		}
4666 	}
4667 	str_name = ZSTR_VAL(name);
4668 	if ((tmp = strstr(ZSTR_VAL(name), "::")) != NULL) {
4669 		classname_len = tmp - ZSTR_VAL(name);
4670 		classname = zend_string_alloc(classname_len, 0);
4671 		zend_str_tolower_copy(ZSTR_VAL(classname), ZSTR_VAL(name), classname_len);
4672 		ZSTR_VAL(classname)[classname_len] = '\0';
4673 		str_name_len = ZSTR_LEN(name) - (classname_len + 2);
4674 		str_name = tmp + 2;
4675 
4676 		ce2 = zend_lookup_class(classname);
4677 		if (!ce2) {
4678 			if (!EG(exception)) {
4679 				zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(classname));
4680 			}
4681 			zend_string_release_ex(classname, 0);
4682 			RETURN_THROWS();
4683 		}
4684 		zend_string_release_ex(classname, 0);
4685 
4686 		if (!instanceof_function(ce, ce2)) {
4687 			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));
4688 			RETURN_THROWS();
4689 		}
4690 		ce = ce2;
4691 
4692 		property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len);
4693 		if (property_info != NULL
4694 		 && (!(property_info->flags & ZEND_ACC_PRIVATE)
4695 		  || property_info->ce == ce)) {
4696 			reflection_property_factory_str(ce, str_name, str_name_len, property_info, return_value);
4697 			return;
4698 		}
4699 	}
4700 	zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), str_name);
4701 }
4702 /* }}} */
4703 
4704 /* {{{ _addproperty */
_addproperty(zend_property_info * pptr,zend_string * key,zend_class_entry * ce,HashTable * ht,long filter)4705 static void _addproperty(zend_property_info *pptr, zend_string *key, zend_class_entry *ce, HashTable *ht, long filter)
4706 {
4707 	if ((pptr->flags & ZEND_ACC_PRIVATE) && pptr->ce != ce) {
4708 		return;
4709 	}
4710 
4711 	if (pptr->flags	& filter) {
4712 		zval property;
4713 		reflection_property_factory(ce, key, pptr, &property);
4714 		zend_hash_next_index_insert_new(ht, &property);
4715 	}
4716 }
4717 /* }}} */
4718 
4719 /* {{{ _adddynproperty */
_adddynproperty(zval * ptr,zend_string * key,zend_class_entry * ce,zval * retval)4720 static void _adddynproperty(zval *ptr, zend_string *key, zend_class_entry *ce, zval *retval)
4721 {
4722 	zval property;
4723 
4724 	/* under some circumstances, the properties hash table may contain numeric
4725 	 * properties (e.g. when casting from array). This is a WON'T FIX bug, at
4726 	 * least for the moment. Ignore these */
4727 	if (key == NULL) {
4728 		return;
4729 	}
4730 
4731 	/* Not a dynamic property */
4732 	if (Z_TYPE_P(ptr) == IS_INDIRECT) {
4733 		return;
4734 	}
4735 
4736 	reflection_property_factory(ce, key, NULL, &property);
4737 	add_next_index_zval(retval, &property);
4738 }
4739 /* }}} */
4740 
4741 /* {{{ Returns an array of this class' properties */
ZEND_METHOD(ReflectionClass,getProperties)4742 ZEND_METHOD(ReflectionClass, getProperties)
4743 {
4744 	reflection_object *intern;
4745 	zend_class_entry *ce;
4746 	zend_string *key;
4747 	zend_property_info *prop_info;
4748 	zend_long filter;
4749 	bool filter_is_null = 1;
4750 
4751 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4752 		RETURN_THROWS();
4753 	}
4754 
4755 	if (filter_is_null) {
4756 		filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC;
4757 	}
4758 
4759 	GET_REFLECTION_OBJECT_PTR(ce);
4760 
4761 	array_init(return_value);
4762 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
4763 		_addproperty(prop_info, key, ce, Z_ARRVAL_P(return_value), filter);
4764 	} ZEND_HASH_FOREACH_END();
4765 
4766 	if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0) {
4767 		HashTable *properties = Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj));
4768 		zval *prop;
4769 		ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, prop) {
4770 			_adddynproperty(prop, key, ce, return_value);
4771 		} ZEND_HASH_FOREACH_END();
4772 	}
4773 }
4774 /* }}} */
4775 
4776 /* {{{ Returns whether a constant exists or not */
ZEND_METHOD(ReflectionClass,hasConstant)4777 ZEND_METHOD(ReflectionClass, hasConstant)
4778 {
4779 	reflection_object *intern;
4780 	zend_class_entry *ce;
4781 	zend_string *name;
4782 
4783 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4784 		RETURN_THROWS();
4785 	}
4786 
4787 	GET_REFLECTION_OBJECT_PTR(ce);
4788 	if (zend_hash_exists(&ce->constants_table, name)) {
4789 		RETURN_TRUE;
4790 	} else {
4791 		RETURN_FALSE;
4792 	}
4793 }
4794 /* }}} */
4795 
4796 /* {{{ Returns an associative array containing this class' constants and their values */
ZEND_METHOD(ReflectionClass,getConstants)4797 ZEND_METHOD(ReflectionClass, getConstants)
4798 {
4799 	reflection_object *intern;
4800 	zend_class_entry *ce;
4801 	zend_string *key;
4802 	zend_class_constant *constant;
4803 	zval val;
4804 	zend_long filter;
4805 	bool filter_is_null = 1;
4806 
4807 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4808 		RETURN_THROWS();
4809 	}
4810 
4811 	if (filter_is_null) {
4812 		filter = ZEND_ACC_PPP_MASK;
4813 	}
4814 
4815 	GET_REFLECTION_OBJECT_PTR(ce);
4816 
4817 	array_init(return_value);
4818 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, constant) {
4819 		if (UNEXPECTED(Z_TYPE(constant->value) == IS_CONSTANT_AST && zend_update_class_constant(constant, key, constant->ce) != SUCCESS)) {
4820 			RETURN_THROWS();
4821 		}
4822 
4823 		if (ZEND_CLASS_CONST_FLAGS(constant) & filter) {
4824 			ZVAL_COPY_OR_DUP(&val, &constant->value);
4825 			zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
4826 		}
4827 	} ZEND_HASH_FOREACH_END();
4828 }
4829 /* }}} */
4830 
4831 /* {{{ Returns an associative array containing this class' constants as ReflectionClassConstant objects */
ZEND_METHOD(ReflectionClass,getReflectionConstants)4832 ZEND_METHOD(ReflectionClass, getReflectionConstants)
4833 {
4834 	reflection_object *intern;
4835 	zend_class_entry *ce;
4836 	zend_string *name;
4837 	zend_class_constant *constant;
4838 	zend_long filter;
4839 	bool filter_is_null = 1;
4840 
4841 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4842 		RETURN_THROWS();
4843 	}
4844 
4845 	if (filter_is_null) {
4846 		filter = ZEND_ACC_PPP_MASK;
4847 	}
4848 
4849 	GET_REFLECTION_OBJECT_PTR(ce);
4850 
4851 	array_init(return_value);
4852 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), name, constant) {
4853 		if (ZEND_CLASS_CONST_FLAGS(constant) & filter) {
4854 			zval class_const;
4855 			reflection_class_constant_factory(name, constant, &class_const);
4856 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &class_const);
4857 		}
4858 	} ZEND_HASH_FOREACH_END();
4859 }
4860 /* }}} */
4861 
4862 /* {{{ Returns the class' constant specified by its name */
ZEND_METHOD(ReflectionClass,getConstant)4863 ZEND_METHOD(ReflectionClass, getConstant)
4864 {
4865 	reflection_object *intern;
4866 	zend_class_entry *ce;
4867 	HashTable *constants_table;
4868 	zend_class_constant *c;
4869 	zend_string *name, *key;
4870 
4871 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4872 		RETURN_THROWS();
4873 	}
4874 
4875 	GET_REFLECTION_OBJECT_PTR(ce);
4876 	constants_table = CE_CONSTANTS_TABLE(ce);
4877 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(constants_table, key, c) {
4878 		if (UNEXPECTED(Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, key, c->ce) != SUCCESS)) {
4879 			RETURN_THROWS();
4880 		}
4881 	} ZEND_HASH_FOREACH_END();
4882 	if ((c = zend_hash_find_ptr(constants_table, name)) == NULL) {
4883 		RETURN_FALSE;
4884 	}
4885 	ZVAL_COPY_OR_DUP(return_value, &c->value);
4886 }
4887 /* }}} */
4888 
4889 /* {{{ Returns the class' constant as ReflectionClassConstant objects */
ZEND_METHOD(ReflectionClass,getReflectionConstant)4890 ZEND_METHOD(ReflectionClass, getReflectionConstant)
4891 {
4892 	reflection_object *intern;
4893 	zend_class_entry *ce;
4894 	zend_class_constant *constant;
4895 	zend_string *name;
4896 
4897 	GET_REFLECTION_OBJECT_PTR(ce);
4898 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4899 		RETURN_THROWS();
4900 	}
4901 
4902 	if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name)) == NULL) {
4903 		RETURN_FALSE;
4904 	}
4905 	reflection_class_constant_factory(name, constant, return_value);
4906 }
4907 /* }}} */
4908 
4909 /* {{{ _class_check_flag */
_class_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)4910 static void _class_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
4911 {
4912 	reflection_object *intern;
4913 	zend_class_entry *ce;
4914 
4915 	if (zend_parse_parameters_none() == FAILURE) {
4916 		RETURN_THROWS();
4917 	}
4918 	GET_REFLECTION_OBJECT_PTR(ce);
4919 	RETVAL_BOOL(ce->ce_flags & mask);
4920 }
4921 /* }}} */
4922 
4923 /* {{{ Returns whether this class is instantiable */
ZEND_METHOD(ReflectionClass,isInstantiable)4924 ZEND_METHOD(ReflectionClass, isInstantiable)
4925 {
4926 	reflection_object *intern;
4927 	zend_class_entry *ce;
4928 
4929 	if (zend_parse_parameters_none() == FAILURE) {
4930 		RETURN_THROWS();
4931 	}
4932 	GET_REFLECTION_OBJECT_PTR(ce);
4933 	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) {
4934 		RETURN_FALSE;
4935 	}
4936 
4937 	/* Basically, the class is instantiable. Though, if there is a constructor
4938 	 * and it is not publicly accessible, it isn't! */
4939 	if (!ce->constructor) {
4940 		RETURN_TRUE;
4941 	}
4942 
4943 	RETURN_BOOL(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC);
4944 }
4945 /* }}} */
4946 
4947 /* {{{ Returns whether this class is cloneable */
ZEND_METHOD(ReflectionClass,isCloneable)4948 ZEND_METHOD(ReflectionClass, isCloneable)
4949 {
4950 	reflection_object *intern;
4951 	zend_class_entry *ce;
4952 	zval obj;
4953 
4954 	if (zend_parse_parameters_none() == FAILURE) {
4955 		RETURN_THROWS();
4956 	}
4957 	GET_REFLECTION_OBJECT_PTR(ce);
4958 	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) {
4959 		RETURN_FALSE;
4960 	}
4961 	if (!Z_ISUNDEF(intern->obj)) {
4962 		if (ce->clone) {
4963 			RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4964 		} else {
4965 			RETURN_BOOL(Z_OBJ_HANDLER(intern->obj, clone_obj) != NULL);
4966 		}
4967 	} else {
4968 		if (ce->clone) {
4969 			RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4970 		} else {
4971 			if (UNEXPECTED(object_init_ex(&obj, ce) != SUCCESS)) {
4972 				return;
4973 			}
4974 			/* We're not calling the constructor, so don't call the destructor either. */
4975 			zend_object_store_ctor_failed(Z_OBJ(obj));
4976 			RETVAL_BOOL(Z_OBJ_HANDLER(obj, clone_obj) != NULL);
4977 			zval_ptr_dtor(&obj);
4978 		}
4979 	}
4980 }
4981 /* }}} */
4982 
4983 /* {{{ Returns whether this is an interface or a class */
ZEND_METHOD(ReflectionClass,isInterface)4984 ZEND_METHOD(ReflectionClass, isInterface)
4985 {
4986 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_INTERFACE);
4987 }
4988 /* }}} */
4989 
4990 /* {{{ Returns whether this is a trait */
ZEND_METHOD(ReflectionClass,isTrait)4991 ZEND_METHOD(ReflectionClass, isTrait)
4992 {
4993 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT);
4994 }
4995 /* }}} */
4996 
ZEND_METHOD(ReflectionClass,isEnum)4997 ZEND_METHOD(ReflectionClass, isEnum)
4998 {
4999 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM);
5000 }
5001 
5002 /* {{{ Returns whether this class is final */
ZEND_METHOD(ReflectionClass,isFinal)5003 ZEND_METHOD(ReflectionClass, isFinal)
5004 {
5005 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
5006 }
5007 /* }}} */
5008 
5009 /* Returns whether this class is readonly */
ZEND_METHOD(ReflectionClass,isReadOnly)5010 ZEND_METHOD(ReflectionClass, isReadOnly)
5011 {
5012 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_READONLY_CLASS);
5013 }
5014 
5015 /* {{{ Returns whether this class is abstract */
ZEND_METHOD(ReflectionClass,isAbstract)5016 ZEND_METHOD(ReflectionClass, isAbstract)
5017 {
5018 	_class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
5019 }
5020 /* }}} */
5021 
5022 /* {{{ Returns a bitfield of the access modifiers for this class */
ZEND_METHOD(ReflectionClass,getModifiers)5023 ZEND_METHOD(ReflectionClass, getModifiers)
5024 {
5025 	reflection_object *intern;
5026 	zend_class_entry *ce;
5027 	uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_READONLY_CLASS;
5028 
5029 	if (zend_parse_parameters_none() == FAILURE) {
5030 		RETURN_THROWS();
5031 	}
5032 	GET_REFLECTION_OBJECT_PTR(ce);
5033 
5034 	RETURN_LONG((ce->ce_flags & keep_flags));
5035 }
5036 /* }}} */
5037 
5038 /* {{{ Returns whether the given object is an instance of this class */
ZEND_METHOD(ReflectionClass,isInstance)5039 ZEND_METHOD(ReflectionClass, isInstance)
5040 {
5041 	reflection_object *intern;
5042 	zend_class_entry *ce;
5043 	zval *object;
5044 
5045 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) {
5046 		RETURN_THROWS();
5047 	}
5048 	GET_REFLECTION_OBJECT_PTR(ce);
5049 	RETURN_BOOL(instanceof_function(Z_OBJCE_P(object), ce));
5050 }
5051 /* }}} */
5052 
5053 /* {{{ Returns an instance of this class */
ZEND_METHOD(ReflectionClass,newInstance)5054 ZEND_METHOD(ReflectionClass, newInstance)
5055 {
5056 	reflection_object *intern;
5057 	zend_class_entry *ce, *old_scope;
5058 	zend_function *constructor;
5059 
5060 	GET_REFLECTION_OBJECT_PTR(ce);
5061 
5062 	if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
5063 		return;
5064 	}
5065 
5066 	old_scope = EG(fake_scope);
5067 	EG(fake_scope) = ce;
5068 	constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
5069 	EG(fake_scope) = old_scope;
5070 
5071 	/* Run the constructor if there is one */
5072 	if (constructor) {
5073 		zval *params;
5074 		int num_args;
5075 		HashTable *named_params;
5076 
5077 		if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
5078 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
5079 			zval_ptr_dtor(return_value);
5080 			RETURN_NULL();
5081 		}
5082 
5083 		ZEND_PARSE_PARAMETERS_START(0, -1)
5084 			Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params)
5085 		ZEND_PARSE_PARAMETERS_END();
5086 
5087 		zend_call_known_function(
5088 			constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL,
5089 			num_args, params, named_params);
5090 
5091 		if (EG(exception)) {
5092 			zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5093 		}
5094 	} else if (ZEND_NUM_ARGS()) {
5095 		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));
5096 	}
5097 }
5098 /* }}} */
5099 
5100 /* {{{ Returns an instance of this class without invoking its constructor */
ZEND_METHOD(ReflectionClass,newInstanceWithoutConstructor)5101 ZEND_METHOD(ReflectionClass, newInstanceWithoutConstructor)
5102 {
5103 	reflection_object *intern;
5104 	zend_class_entry *ce;
5105 
5106 	GET_REFLECTION_OBJECT_PTR(ce);
5107 
5108 	if (zend_parse_parameters_none() == FAILURE) {
5109 		RETURN_THROWS();
5110 	}
5111 
5112 	if (ce->type == ZEND_INTERNAL_CLASS
5113 			&& ce->create_object != NULL && (ce->ce_flags & ZEND_ACC_FINAL)) {
5114 		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));
5115 		RETURN_THROWS();
5116 	}
5117 
5118 	object_init_ex(return_value, ce);
5119 }
5120 /* }}} */
5121 
5122 /* {{{ Returns an instance of this class */
ZEND_METHOD(ReflectionClass,newInstanceArgs)5123 ZEND_METHOD(ReflectionClass, newInstanceArgs)
5124 {
5125 	reflection_object *intern;
5126 	zend_class_entry *ce, *old_scope;
5127 	int argc = 0;
5128 	HashTable *args = NULL;
5129 	zend_function *constructor;
5130 
5131 	GET_REFLECTION_OBJECT_PTR(ce);
5132 
5133 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|h", &args) == FAILURE) {
5134 		RETURN_THROWS();
5135 	}
5136 
5137 	if (args) {
5138 		argc = zend_hash_num_elements(args);
5139 	}
5140 
5141 	if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
5142 		return;
5143 	}
5144 
5145 	old_scope = EG(fake_scope);
5146 	EG(fake_scope) = ce;
5147 	constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
5148 	EG(fake_scope) = old_scope;
5149 
5150 	/* Run the constructor if there is one */
5151 	if (constructor) {
5152 		if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
5153 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
5154 			zval_ptr_dtor(return_value);
5155 			RETURN_NULL();
5156 		}
5157 
5158 		zend_call_known_function(
5159 			constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, 0, NULL, args);
5160 
5161 		if (EG(exception)) {
5162 			zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5163 		}
5164 	} else if (argc) {
5165 		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));
5166 	}
5167 }
5168 /* }}} */
5169 
5170 /* {{{ Returns an array of interfaces this class implements */
ZEND_METHOD(ReflectionClass,getInterfaces)5171 ZEND_METHOD(ReflectionClass, getInterfaces)
5172 {
5173 	reflection_object *intern;
5174 	zend_class_entry *ce;
5175 
5176 	if (zend_parse_parameters_none() == FAILURE) {
5177 		RETURN_THROWS();
5178 	}
5179 	GET_REFLECTION_OBJECT_PTR(ce);
5180 
5181 	if (ce->num_interfaces) {
5182 		uint32_t i;
5183 
5184 		ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
5185 		array_init(return_value);
5186 		for (i=0; i < ce->num_interfaces; i++) {
5187 			zval interface;
5188 			zend_reflection_class_factory(ce->interfaces[i], &interface);
5189 			zend_hash_update(Z_ARRVAL_P(return_value), ce->interfaces[i]->name, &interface);
5190 		}
5191 	} else {
5192 		RETURN_EMPTY_ARRAY();
5193 	}
5194 }
5195 /* }}} */
5196 
5197 /* {{{ Returns an array of names of interfaces this class implements */
ZEND_METHOD(ReflectionClass,getInterfaceNames)5198 ZEND_METHOD(ReflectionClass, getInterfaceNames)
5199 {
5200 	reflection_object *intern;
5201 	zend_class_entry *ce;
5202 	uint32_t i;
5203 
5204 	if (zend_parse_parameters_none() == FAILURE) {
5205 		RETURN_THROWS();
5206 	}
5207 	GET_REFLECTION_OBJECT_PTR(ce);
5208 
5209 	if (!ce->num_interfaces) {
5210 		/* Return an empty array if this class implements no interfaces */
5211 		RETURN_EMPTY_ARRAY();
5212 	}
5213 
5214 	ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
5215 	array_init(return_value);
5216 
5217 	for (i=0; i < ce->num_interfaces; i++) {
5218 		add_next_index_str(return_value, zend_string_copy(ce->interfaces[i]->name));
5219 	}
5220 }
5221 /* }}} */
5222 
5223 /* {{{ Returns an array of traits used by this class */
ZEND_METHOD(ReflectionClass,getTraits)5224 ZEND_METHOD(ReflectionClass, getTraits)
5225 {
5226 	reflection_object *intern;
5227 	zend_class_entry *ce;
5228 	uint32_t i;
5229 
5230 	if (zend_parse_parameters_none() == FAILURE) {
5231 		RETURN_THROWS();
5232 	}
5233 	GET_REFLECTION_OBJECT_PTR(ce);
5234 
5235 	if (!ce->num_traits) {
5236 		RETURN_EMPTY_ARRAY();
5237 	}
5238 
5239 	array_init(return_value);
5240 
5241 	for (i=0; i < ce->num_traits; i++) {
5242 		zval trait;
5243 		zend_class_entry *trait_ce;
5244 
5245 		trait_ce = zend_fetch_class_by_name(ce->trait_names[i].name,
5246 			ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
5247 		ZEND_ASSERT(trait_ce);
5248 		zend_reflection_class_factory(trait_ce, &trait);
5249 		zend_hash_update(Z_ARRVAL_P(return_value), ce->trait_names[i].name, &trait);
5250 	}
5251 }
5252 /* }}} */
5253 
5254 /* {{{ Returns an array of names of traits used by this class */
ZEND_METHOD(ReflectionClass,getTraitNames)5255 ZEND_METHOD(ReflectionClass, getTraitNames)
5256 {
5257 	reflection_object *intern;
5258 	zend_class_entry *ce;
5259 	uint32_t i;
5260 
5261 	if (zend_parse_parameters_none() == FAILURE) {
5262 		RETURN_THROWS();
5263 	}
5264 	GET_REFLECTION_OBJECT_PTR(ce);
5265 
5266 	if (!ce->num_traits) {
5267 		RETURN_EMPTY_ARRAY();
5268 	}
5269 
5270 	array_init(return_value);
5271 
5272 	for (i=0; i < ce->num_traits; i++) {
5273 		add_next_index_str(return_value, zend_string_copy(ce->trait_names[i].name));
5274 	}
5275 }
5276 /* }}} */
5277 
5278 /* {{{ Returns an array of trait aliases */
ZEND_METHOD(ReflectionClass,getTraitAliases)5279 ZEND_METHOD(ReflectionClass, getTraitAliases)
5280 {
5281 	reflection_object *intern;
5282 	zend_class_entry *ce;
5283 
5284 	if (zend_parse_parameters_none() == FAILURE) {
5285 		RETURN_THROWS();
5286 	}
5287 	GET_REFLECTION_OBJECT_PTR(ce);
5288 
5289 
5290 	if (ce->trait_aliases) {
5291 		uint32_t i = 0;
5292 
5293 		array_init(return_value);
5294 		while (ce->trait_aliases[i]) {
5295 			zend_string *mname;
5296 			zend_trait_method_reference *cur_ref = &ce->trait_aliases[i]->trait_method;
5297 
5298 			if (ce->trait_aliases[i]->alias) {
5299 				zend_string *class_name = cur_ref->class_name;
5300 
5301 				if (!class_name) {
5302 					uint32_t j = 0;
5303 					zend_string *lcname = zend_string_tolower(cur_ref->method_name);
5304 
5305 					for (j = 0; j < ce->num_traits; j++) {
5306 						zend_class_entry *trait =
5307 							zend_hash_find_ptr(CG(class_table), ce->trait_names[j].lc_name);
5308 						ZEND_ASSERT(trait && "Trait must exist");
5309 						if (zend_hash_exists(&trait->function_table, lcname)) {
5310 							class_name = trait->name;
5311 							break;
5312 						}
5313 					}
5314 					zend_string_release_ex(lcname, 0);
5315 					ZEND_ASSERT(class_name != NULL);
5316 				}
5317 
5318 				mname = zend_string_alloc(ZSTR_LEN(class_name) + ZSTR_LEN(cur_ref->method_name) + 2, 0);
5319 				snprintf(ZSTR_VAL(mname), ZSTR_LEN(mname) + 1, "%s::%s", ZSTR_VAL(class_name), ZSTR_VAL(cur_ref->method_name));
5320 				add_assoc_str_ex(return_value, ZSTR_VAL(ce->trait_aliases[i]->alias), ZSTR_LEN(ce->trait_aliases[i]->alias), mname);
5321 			}
5322 			i++;
5323 		}
5324 	} else {
5325 		RETURN_EMPTY_ARRAY();
5326 	}
5327 }
5328 /* }}} */
5329 
5330 /* {{{ Returns the class' parent class, or, if none exists, FALSE */
ZEND_METHOD(ReflectionClass,getParentClass)5331 ZEND_METHOD(ReflectionClass, getParentClass)
5332 {
5333 	reflection_object *intern;
5334 	zend_class_entry *ce;
5335 
5336 	if (zend_parse_parameters_none() == FAILURE) {
5337 		RETURN_THROWS();
5338 	}
5339 	GET_REFLECTION_OBJECT_PTR(ce);
5340 
5341 	if (ce->parent) {
5342 		zend_reflection_class_factory(ce->parent, return_value);
5343 	} else {
5344 		RETURN_FALSE;
5345 	}
5346 }
5347 /* }}} */
5348 
5349 /* {{{ Returns whether this class is a subclass of another class */
ZEND_METHOD(ReflectionClass,isSubclassOf)5350 ZEND_METHOD(ReflectionClass, isSubclassOf)
5351 {
5352 	reflection_object *intern, *argument;
5353 	zend_class_entry *ce, *class_ce;
5354 	zend_string *class_str;
5355 	zend_object *class_obj;
5356 
5357 	ZEND_PARSE_PARAMETERS_START(1, 1)
5358 		Z_PARAM_OBJ_OF_CLASS_OR_STR(class_obj, reflection_class_ptr, class_str)
5359 	ZEND_PARSE_PARAMETERS_END();
5360 
5361 	if (class_obj) {
5362 		argument = reflection_object_from_obj(class_obj);
5363 		if (argument->ptr == NULL) {
5364 			zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5365 			RETURN_THROWS();
5366 		}
5367 
5368 		class_ce = argument->ptr;
5369 	} else {
5370 		if ((class_ce = zend_lookup_class(class_str)) == NULL) {
5371 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(class_str));
5372 			RETURN_THROWS();
5373 		}
5374 	}
5375 
5376 	GET_REFLECTION_OBJECT_PTR(ce);
5377 
5378 	RETURN_BOOL((ce != class_ce && instanceof_function(ce, class_ce)));
5379 }
5380 /* }}} */
5381 
5382 /* {{{ Returns whether this class is a subclass of another class */
ZEND_METHOD(ReflectionClass,implementsInterface)5383 ZEND_METHOD(ReflectionClass, implementsInterface)
5384 {
5385 	reflection_object *intern, *argument;
5386 	zend_string *interface_str;
5387 	zend_class_entry *ce, *interface_ce;
5388 	zend_object *interface_obj;
5389 
5390 	ZEND_PARSE_PARAMETERS_START(1, 1)
5391 		Z_PARAM_OBJ_OF_CLASS_OR_STR(interface_obj, reflection_class_ptr, interface_str)
5392 	ZEND_PARSE_PARAMETERS_END();
5393 
5394 	if (interface_obj) {
5395 		argument = reflection_object_from_obj(interface_obj);
5396 		if (argument->ptr == NULL) {
5397 			zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5398 			RETURN_THROWS();
5399 		}
5400 
5401 		interface_ce = argument->ptr;
5402 	} else {
5403 		if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
5404 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Interface \"%s\" does not exist", ZSTR_VAL(interface_str));
5405 			RETURN_THROWS();
5406 		}
5407 	}
5408 
5409 	if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) {
5410 		zend_throw_exception_ex(reflection_exception_ptr, 0, "%s is not an interface", ZSTR_VAL(interface_ce->name));
5411 		RETURN_THROWS();
5412 	}
5413 
5414 	GET_REFLECTION_OBJECT_PTR(ce);
5415 
5416 	RETURN_BOOL(instanceof_function(ce, interface_ce));
5417 }
5418 /* }}} */
5419 
5420 /* {{{ Returns whether this class is iterable (can be used inside foreach) */
ZEND_METHOD(ReflectionClass,isIterable)5421 ZEND_METHOD(ReflectionClass, isIterable)
5422 {
5423 	reflection_object *intern;
5424 	zend_class_entry *ce;
5425 
5426 	if (zend_parse_parameters_none() == FAILURE) {
5427 		RETURN_THROWS();
5428 	}
5429 
5430 	GET_REFLECTION_OBJECT_PTR(ce);
5431 
5432 	if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS |
5433 	                    ZEND_ACC_TRAIT     | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
5434 		RETURN_FALSE;
5435 	}
5436 
5437 	RETURN_BOOL(ce->get_iterator || instanceof_function(ce, zend_ce_traversable));
5438 }
5439 /* }}} */
5440 
5441 /* {{{ Returns NULL or the extension the class belongs to */
ZEND_METHOD(ReflectionClass,getExtension)5442 ZEND_METHOD(ReflectionClass, getExtension)
5443 {
5444 	reflection_object *intern;
5445 	zend_class_entry *ce;
5446 
5447 	if (zend_parse_parameters_none() == FAILURE) {
5448 		RETURN_THROWS();
5449 	}
5450 
5451 	GET_REFLECTION_OBJECT_PTR(ce);
5452 
5453 	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5454 		reflection_extension_factory(return_value, ce->info.internal.module->name);
5455 	}
5456 }
5457 /* }}} */
5458 
5459 /* {{{ Returns false or the name of the extension the class belongs to */
ZEND_METHOD(ReflectionClass,getExtensionName)5460 ZEND_METHOD(ReflectionClass, getExtensionName)
5461 {
5462 	reflection_object *intern;
5463 	zend_class_entry *ce;
5464 
5465 	if (zend_parse_parameters_none() == FAILURE) {
5466 		RETURN_THROWS();
5467 	}
5468 
5469 	GET_REFLECTION_OBJECT_PTR(ce);
5470 
5471 	if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5472 		RETURN_STRING(ce->info.internal.module->name);
5473 	} else {
5474 		RETURN_FALSE;
5475 	}
5476 }
5477 /* }}} */
5478 
5479 /* {{{ Returns whether this class is defined in namespace */
ZEND_METHOD(ReflectionClass,inNamespace)5480 ZEND_METHOD(ReflectionClass, inNamespace)
5481 {
5482 	reflection_object *intern;
5483 	zend_class_entry *ce;
5484 
5485 	if (zend_parse_parameters_none() == FAILURE) {
5486 		RETURN_THROWS();
5487 	}
5488 
5489 	GET_REFLECTION_OBJECT_PTR(ce);
5490 
5491 	zend_string *name = ce->name;
5492 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5493 	RETURN_BOOL(backslash);
5494 }
5495 /* }}} */
5496 
5497 /* {{{ Returns the name of namespace where this class is defined */
ZEND_METHOD(ReflectionClass,getNamespaceName)5498 ZEND_METHOD(ReflectionClass, getNamespaceName)
5499 {
5500 	reflection_object *intern;
5501 	zend_class_entry *ce;
5502 
5503 	if (zend_parse_parameters_none() == FAILURE) {
5504 		RETURN_THROWS();
5505 	}
5506 
5507 	GET_REFLECTION_OBJECT_PTR(ce);
5508 
5509 	zend_string *name = ce->name;
5510 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5511 	if (backslash) {
5512 		RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
5513 	}
5514 	RETURN_EMPTY_STRING();
5515 }
5516 /* }}} */
5517 
5518 /* {{{ Returns the short name of the class (without namespace part) */
ZEND_METHOD(ReflectionClass,getShortName)5519 ZEND_METHOD(ReflectionClass, getShortName)
5520 {
5521 	reflection_object *intern;
5522 	zend_class_entry *ce;
5523 
5524 	if (zend_parse_parameters_none() == FAILURE) {
5525 		RETURN_THROWS();
5526 	}
5527 
5528 	GET_REFLECTION_OBJECT_PTR(ce);
5529 
5530 	zend_string *name = ce->name;
5531 	const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5532 	if (backslash) {
5533 		RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
5534 	}
5535 	RETURN_STR_COPY(name);
5536 }
5537 /* }}} */
5538 
5539 /* {{{ Constructor. Takes an instance as an argument */
ZEND_METHOD(ReflectionObject,__construct)5540 ZEND_METHOD(ReflectionObject, __construct)
5541 {
5542 	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
5543 }
5544 /* }}} */
5545 
5546 /* {{{ Constructor. Throws an Exception in case the given property does not exist */
ZEND_METHOD(ReflectionProperty,__construct)5547 ZEND_METHOD(ReflectionProperty, __construct)
5548 {
5549 	zend_string *classname_str;
5550 	zend_object *classname_obj;
5551 	zend_string *name;
5552 	int dynam_prop = 0;
5553 	zval *object;
5554 	reflection_object *intern;
5555 	zend_class_entry *ce;
5556 	zend_property_info *property_info = NULL;
5557 	property_reference *reference;
5558 
5559 	ZEND_PARSE_PARAMETERS_START(2, 2)
5560 		Z_PARAM_OBJ_OR_STR(classname_obj, classname_str)
5561 		Z_PARAM_STR(name)
5562 	ZEND_PARSE_PARAMETERS_END();
5563 
5564 	object = ZEND_THIS;
5565 	intern = Z_REFLECTION_P(object);
5566 
5567 	if (classname_obj) {
5568 		ce = classname_obj->ce;
5569 	} else {
5570 		if ((ce = zend_lookup_class(classname_str)) == NULL) {
5571 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%s\" does not exist", ZSTR_VAL(classname_str));
5572 			RETURN_THROWS();
5573 		}
5574 	}
5575 
5576 	property_info = zend_hash_find_ptr(&ce->properties_info, name);
5577 	if (property_info == NULL
5578 	 || ((property_info->flags & ZEND_ACC_PRIVATE)
5579 	  && property_info->ce != ce)) {
5580 		/* Check for dynamic properties */
5581 		if (property_info == NULL && classname_obj) {
5582 			if (zend_hash_exists(classname_obj->handlers->get_properties(classname_obj), name)) {
5583 				dynam_prop = 1;
5584 			}
5585 		}
5586 		if (dynam_prop == 0) {
5587 			zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %s::$%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
5588 			RETURN_THROWS();
5589 		}
5590 	}
5591 
5592 	ZVAL_STR_COPY(reflection_prop_name(object), name);
5593 	if (dynam_prop == 0) {
5594 		ZVAL_STR_COPY(reflection_prop_class(object), property_info->ce->name);
5595 	} else {
5596 		ZVAL_STR_COPY(reflection_prop_class(object), ce->name);
5597 	}
5598 
5599 	reference = (property_reference*) emalloc(sizeof(property_reference));
5600 	reference->prop = dynam_prop ? NULL : property_info;
5601 	reference->unmangled_name = zend_string_copy(name);
5602 	intern->ptr = reference;
5603 	intern->ref_type = REF_TYPE_PROPERTY;
5604 	intern->ce = ce;
5605 }
5606 /* }}} */
5607 
5608 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionProperty,__toString)5609 ZEND_METHOD(ReflectionProperty, __toString)
5610 {
5611 	reflection_object *intern;
5612 	property_reference *ref;
5613 	smart_str str = {0};
5614 
5615 	if (zend_parse_parameters_none() == FAILURE) {
5616 		RETURN_THROWS();
5617 	}
5618 	GET_REFLECTION_OBJECT_PTR(ref);
5619 	_property_string(&str, ref->prop, ZSTR_VAL(ref->unmangled_name), "");
5620 	RETURN_STR(smart_str_extract(&str));
5621 }
5622 /* }}} */
5623 
5624 /* {{{ Returns the class' name */
ZEND_METHOD(ReflectionProperty,getName)5625 ZEND_METHOD(ReflectionProperty, getName)
5626 {
5627 	reflection_object *intern;
5628 	property_reference *ref;
5629 
5630 	if (zend_parse_parameters_none() == FAILURE) {
5631 		RETURN_THROWS();
5632 	}
5633 
5634 	GET_REFLECTION_OBJECT_PTR(ref);
5635 	RETURN_STR_COPY(ref->unmangled_name);
5636 }
5637 /* }}} */
5638 
_property_check_flag(INTERNAL_FUNCTION_PARAMETERS,int mask)5639 static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
5640 {
5641 	reflection_object *intern;
5642 	property_reference *ref;
5643 
5644 	if (zend_parse_parameters_none() == FAILURE) {
5645 		RETURN_THROWS();
5646 	}
5647 	GET_REFLECTION_OBJECT_PTR(ref);
5648 	RETURN_BOOL(prop_get_flags(ref) & mask);
5649 }
5650 /* }}} */
5651 
5652 /* {{{ Returns whether this property is public */
ZEND_METHOD(ReflectionProperty,isPublic)5653 ZEND_METHOD(ReflectionProperty, isPublic)
5654 {
5655 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
5656 }
5657 /* }}} */
5658 
5659 /* {{{ Returns whether this property is private */
ZEND_METHOD(ReflectionProperty,isPrivate)5660 ZEND_METHOD(ReflectionProperty, isPrivate)
5661 {
5662 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
5663 }
5664 /* }}} */
5665 
5666 /* {{{ Returns whether this property is protected */
ZEND_METHOD(ReflectionProperty,isProtected)5667 ZEND_METHOD(ReflectionProperty, isProtected)
5668 {
5669 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
5670 }
5671 /* }}} */
5672 
5673 /* {{{ Returns whether this property is static */
ZEND_METHOD(ReflectionProperty,isStatic)5674 ZEND_METHOD(ReflectionProperty, isStatic)
5675 {
5676 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
5677 }
5678 /* }}} */
5679 
ZEND_METHOD(ReflectionProperty,isReadOnly)5680 ZEND_METHOD(ReflectionProperty, isReadOnly)
5681 {
5682 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_READONLY);
5683 }
5684 
5685 /* {{{ Returns whether this property is default (declared at compilation time). */
ZEND_METHOD(ReflectionProperty,isDefault)5686 ZEND_METHOD(ReflectionProperty, isDefault)
5687 {
5688 	reflection_object *intern;
5689 	property_reference *ref;
5690 
5691 	if (zend_parse_parameters_none() == FAILURE) {
5692 		RETURN_THROWS();
5693 	}
5694 	GET_REFLECTION_OBJECT_PTR(ref);
5695 	RETURN_BOOL(ref->prop != NULL);
5696 }
5697 /* }}} */
5698 
5699 /* {{{ Returns whether this property has been promoted from a constructor */
ZEND_METHOD(ReflectionProperty,isPromoted)5700 ZEND_METHOD(ReflectionProperty, isPromoted)
5701 {
5702 	_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROMOTED);
5703 }
5704 /* }}} */
5705 
5706 /* {{{ Returns a bitfield of the access modifiers for this property */
ZEND_METHOD(ReflectionProperty,getModifiers)5707 ZEND_METHOD(ReflectionProperty, getModifiers)
5708 {
5709 	reflection_object *intern;
5710 	property_reference *ref;
5711 	uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY;
5712 
5713 	if (zend_parse_parameters_none() == FAILURE) {
5714 		RETURN_THROWS();
5715 	}
5716 	GET_REFLECTION_OBJECT_PTR(ref);
5717 
5718 	RETURN_LONG(prop_get_flags(ref) & keep_flags);
5719 }
5720 /* }}} */
5721 
5722 /* {{{ Returns this property's value */
ZEND_METHOD(ReflectionProperty,getValue)5723 ZEND_METHOD(ReflectionProperty, getValue)
5724 {
5725 	reflection_object *intern;
5726 	property_reference *ref;
5727 	zval *object = NULL;
5728 	zval *member_p = NULL;
5729 
5730 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) {
5731 		RETURN_THROWS();
5732 	}
5733 
5734 	GET_REFLECTION_OBJECT_PTR(ref);
5735 
5736 	if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5737 		member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 0);
5738 		if (member_p) {
5739 			RETURN_COPY_DEREF(member_p);
5740 		}
5741 	} else {
5742 		zval rv;
5743 
5744 		if (!object) {
5745 			zend_argument_type_error(1, "must be provided for instance properties");
5746 			RETURN_THROWS();
5747 		}
5748 
5749 		/* TODO: Should this always use intern->ce? */
5750 		if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5751 			_DO_THROW("Given object is not an instance of the class this property was declared in");
5752 			RETURN_THROWS();
5753 		}
5754 
5755 		member_p = zend_read_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, 0, &rv);
5756 		if (member_p != &rv) {
5757 			RETURN_COPY_DEREF(member_p);
5758 		} else {
5759 			if (Z_ISREF_P(member_p)) {
5760 				zend_unwrap_reference(member_p);
5761 			}
5762 			RETURN_COPY_VALUE(member_p);
5763 		}
5764 	}
5765 }
5766 /* }}} */
5767 
5768 /* {{{ Sets this property's value */
ZEND_METHOD(ReflectionProperty,setValue)5769 ZEND_METHOD(ReflectionProperty, setValue)
5770 {
5771 	reflection_object *intern;
5772 	property_reference *ref;
5773 	zval *object;
5774 	zval *value;
5775 	zval *tmp;
5776 
5777 	GET_REFLECTION_OBJECT_PTR(ref);
5778 
5779 	if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5780 		if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
5781 			if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &tmp, &value) == FAILURE) {
5782 				RETURN_THROWS();
5783 			}
5784 
5785 			if (Z_TYPE_P(tmp) != IS_NULL && Z_TYPE_P(tmp) != IS_OBJECT) {
5786 				zend_string *method_name = get_active_function_or_method_name();
5787 				zend_error(E_DEPRECATED, "Calling %s() with a 1st argument which is not null or an object is deprecated", ZSTR_VAL(method_name));
5788 				zend_string_release(method_name);
5789 				if (UNEXPECTED(EG(exception))) {
5790 					RETURN_THROWS();
5791 				}
5792 			}
5793 		} else {
5794 			zend_string *method_name = get_active_function_or_method_name();
5795 			zend_error(E_DEPRECATED, "Calling %s() with a single argument is deprecated", ZSTR_VAL(method_name));
5796 			zend_string_release(method_name);
5797 			if (UNEXPECTED(EG(exception))) {
5798 				RETURN_THROWS();
5799 			}
5800 		}
5801 
5802 		zend_update_static_property_ex(intern->ce, ref->unmangled_name, value);
5803 	} else {
5804 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "oz", &object, &value) == FAILURE) {
5805 			RETURN_THROWS();
5806 		}
5807 
5808 		zend_update_property_ex(intern->ce, Z_OBJ_P(object), ref->unmangled_name, value);
5809 	}
5810 }
5811 /* }}} */
5812 
5813 /* {{{ Returns true if property was initialized */
ZEND_METHOD(ReflectionProperty,isInitialized)5814 ZEND_METHOD(ReflectionProperty, isInitialized)
5815 {
5816 	reflection_object *intern;
5817 	property_reference *ref;
5818 	zval *object = NULL;
5819 	zval *member_p = NULL;
5820 
5821 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &object) == FAILURE) {
5822 		RETURN_THROWS();
5823 	}
5824 
5825 	GET_REFLECTION_OBJECT_PTR(ref);
5826 
5827 	if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5828 		member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, 1);
5829 		if (member_p) {
5830 			RETURN_BOOL(!Z_ISUNDEF_P(member_p));
5831 		}
5832 		RETURN_FALSE;
5833 	} else {
5834 		zend_class_entry *old_scope;
5835 		int retval;
5836 
5837 		if (!object) {
5838 			zend_argument_type_error(1, "must be provided for instance properties");
5839 			RETURN_THROWS();
5840 		}
5841 
5842 		/* TODO: Should this always use intern->ce? */
5843 		if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5844 			_DO_THROW("Given object is not an instance of the class this property was declared in");
5845 			RETURN_THROWS();
5846 		}
5847 
5848 		old_scope = EG(fake_scope);
5849 		EG(fake_scope) = intern->ce;
5850 		retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object), ref->unmangled_name, ZEND_PROPERTY_EXISTS, NULL);
5851 		EG(fake_scope) = old_scope;
5852 
5853 		RETVAL_BOOL(retval);
5854 	}
5855 }
5856 /* }}} */
5857 
5858 /* {{{ Get the declaring class */
ZEND_METHOD(ReflectionProperty,getDeclaringClass)5859 ZEND_METHOD(ReflectionProperty, getDeclaringClass)
5860 {
5861 	reflection_object *intern;
5862 	property_reference *ref;
5863 	zend_class_entry *ce;
5864 
5865 	if (zend_parse_parameters_none() == FAILURE) {
5866 		RETURN_THROWS();
5867 	}
5868 	GET_REFLECTION_OBJECT_PTR(ref);
5869 
5870 	ce = ref->prop ? ref->prop->ce : intern->ce;
5871 	zend_reflection_class_factory(ce, return_value);
5872 }
5873 /* }}} */
5874 
5875 /* {{{ Returns the doc comment for this property */
ZEND_METHOD(ReflectionProperty,getDocComment)5876 ZEND_METHOD(ReflectionProperty, getDocComment)
5877 {
5878 	reflection_object *intern;
5879 	property_reference *ref;
5880 
5881 	if (zend_parse_parameters_none() == FAILURE) {
5882 		RETURN_THROWS();
5883 	}
5884 	GET_REFLECTION_OBJECT_PTR(ref);
5885 	if (ref->prop && ref->prop->doc_comment) {
5886 		RETURN_STR_COPY(ref->prop->doc_comment);
5887 	}
5888 	RETURN_FALSE;
5889 }
5890 /* }}} */
5891 
5892 /* {{{ Returns the attributes of this property */
ZEND_METHOD(ReflectionProperty,getAttributes)5893 ZEND_METHOD(ReflectionProperty, getAttributes)
5894 {
5895 	reflection_object *intern;
5896 	property_reference *ref;
5897 
5898 	GET_REFLECTION_OBJECT_PTR(ref);
5899 
5900 	if (ref->prop == NULL) {
5901 		RETURN_EMPTY_ARRAY();
5902 	}
5903 
5904 	reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
5905 		ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY,
5906 		ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL);
5907 }
5908 /* }}} */
5909 
5910 /* {{{ Sets whether non-public properties can be requested */
ZEND_METHOD(ReflectionProperty,setAccessible)5911 ZEND_METHOD(ReflectionProperty, setAccessible)
5912 {
5913 	bool visible;
5914 
5915 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
5916 		RETURN_THROWS();
5917 	}
5918 }
5919 /* }}} */
5920 
5921 /* {{{ Returns the type associated with the property */
ZEND_METHOD(ReflectionProperty,getType)5922 ZEND_METHOD(ReflectionProperty, getType)
5923 {
5924 	reflection_object *intern;
5925 	property_reference *ref;
5926 
5927 	if (zend_parse_parameters_none() == FAILURE) {
5928 		RETURN_THROWS();
5929 	}
5930 
5931 	GET_REFLECTION_OBJECT_PTR(ref);
5932 
5933 	if (!ref->prop || !ZEND_TYPE_IS_SET(ref->prop->type)) {
5934 		RETURN_NULL();
5935 	}
5936 
5937 	reflection_type_factory(ref->prop->type, return_value, 1);
5938 }
5939 /* }}} */
5940 
5941 /* {{{ Returns whether property has a type */
ZEND_METHOD(ReflectionProperty,hasType)5942 ZEND_METHOD(ReflectionProperty, hasType)
5943 {
5944 	reflection_object *intern;
5945 	property_reference *ref;
5946 
5947 	if (zend_parse_parameters_none() == FAILURE) {
5948 		RETURN_THROWS();
5949 	}
5950 
5951 	GET_REFLECTION_OBJECT_PTR(ref);
5952 
5953 	RETVAL_BOOL(ref->prop && ZEND_TYPE_IS_SET(ref->prop->type));
5954 }
5955 /* }}} */
5956 
5957 /* {{{ Returns whether property has a default value */
ZEND_METHOD(ReflectionProperty,hasDefaultValue)5958 ZEND_METHOD(ReflectionProperty, hasDefaultValue)
5959 {
5960 	reflection_object *intern;
5961 	property_reference *ref;
5962 	zend_property_info *prop_info;
5963 	zval *prop;
5964 
5965 	if (zend_parse_parameters_none() == FAILURE) {
5966 		RETURN_THROWS();
5967 	}
5968 
5969 	GET_REFLECTION_OBJECT_PTR(ref);
5970 
5971 	prop_info = ref->prop;
5972 
5973 	if (prop_info == NULL) {
5974 		RETURN_FALSE;
5975 	}
5976 
5977 	prop = property_get_default(prop_info);
5978 	RETURN_BOOL(!Z_ISUNDEF_P(prop));
5979 }
5980 /* }}} */
5981 
5982 /* {{{ Returns the default value of a property */
ZEND_METHOD(ReflectionProperty,getDefaultValue)5983 ZEND_METHOD(ReflectionProperty, getDefaultValue)
5984 {
5985 	reflection_object *intern;
5986 	property_reference *ref;
5987 	zend_property_info *prop_info;
5988 	zval *prop;
5989 
5990 	if (zend_parse_parameters_none() == FAILURE) {
5991 		RETURN_THROWS();
5992 	}
5993 
5994 	GET_REFLECTION_OBJECT_PTR(ref);
5995 
5996 	prop_info = ref->prop;
5997 
5998 	if (prop_info == NULL) {
5999 		return; // throw exception?
6000 	}
6001 
6002 	prop = property_get_default(prop_info);
6003 	if (Z_ISUNDEF_P(prop)) {
6004 		return;
6005 	}
6006 
6007 	/* copy: enforce read only access */
6008 	ZVAL_DEREF(prop);
6009 	ZVAL_COPY_OR_DUP(return_value, prop);
6010 
6011 	/* this is necessary to make it able to work with default array
6012 	* properties, returned to user */
6013 	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
6014 		if (UNEXPECTED(zval_update_constant_ex(return_value, prop_info->ce) != SUCCESS)) {
6015 			RETURN_THROWS();
6016 		}
6017 	}
6018 }
6019 /* }}} */
6020 
6021 /* {{{ Constructor. Throws an Exception in case the given extension does not exist */
ZEND_METHOD(ReflectionExtension,__construct)6022 ZEND_METHOD(ReflectionExtension, __construct)
6023 {
6024 	zval *object;
6025 	char *lcname;
6026 	reflection_object *intern;
6027 	zend_module_entry *module;
6028 	char *name_str;
6029 	size_t name_len;
6030 	ALLOCA_FLAG(use_heap)
6031 
6032 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
6033 		RETURN_THROWS();
6034 	}
6035 
6036 	object = ZEND_THIS;
6037 	intern = Z_REFLECTION_P(object);
6038 	lcname = do_alloca(name_len + 1, use_heap);
6039 	zend_str_tolower_copy(lcname, name_str, name_len);
6040 	if ((module = zend_hash_str_find_ptr(&module_registry, lcname, name_len)) == NULL) {
6041 		free_alloca(lcname, use_heap);
6042 		zend_throw_exception_ex(reflection_exception_ptr, 0,
6043 			"Extension \"%s\" does not exist", name_str);
6044 		RETURN_THROWS();
6045 	}
6046 	free_alloca(lcname, use_heap);
6047 	ZVAL_STRING(reflection_prop_name(object), module->name);
6048 	intern->ptr = module;
6049 	intern->ref_type = REF_TYPE_OTHER;
6050 	intern->ce = NULL;
6051 }
6052 /* }}} */
6053 
6054 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionExtension,__toString)6055 ZEND_METHOD(ReflectionExtension, __toString)
6056 {
6057 	reflection_object *intern;
6058 	zend_module_entry *module;
6059 	smart_str str = {0};
6060 
6061 	if (zend_parse_parameters_none() == FAILURE) {
6062 		RETURN_THROWS();
6063 	}
6064 	GET_REFLECTION_OBJECT_PTR(module);
6065 	_extension_string(&str, module, "");
6066 	RETURN_STR(smart_str_extract(&str));
6067 }
6068 /* }}} */
6069 
6070 /* {{{ Returns this extension's name */
ZEND_METHOD(ReflectionExtension,getName)6071 ZEND_METHOD(ReflectionExtension, getName)
6072 {
6073 	reflection_object *intern;
6074 	zend_module_entry *module;
6075 
6076 	if (zend_parse_parameters_none() == FAILURE) {
6077 		RETURN_THROWS();
6078 	}
6079 
6080 	GET_REFLECTION_OBJECT_PTR(module);
6081 	RETURN_STRING(module->name);
6082 }
6083 /* }}} */
6084 
6085 /* {{{ Returns this extension's version */
ZEND_METHOD(ReflectionExtension,getVersion)6086 ZEND_METHOD(ReflectionExtension, getVersion)
6087 {
6088 	reflection_object *intern;
6089 	zend_module_entry *module;
6090 
6091 	if (zend_parse_parameters_none() == FAILURE) {
6092 		RETURN_THROWS();
6093 	}
6094 	GET_REFLECTION_OBJECT_PTR(module);
6095 
6096 	/* An extension does not necessarily have a version number */
6097 	if (module->version == NO_VERSION_YET) {
6098 		RETURN_NULL();
6099 	} else {
6100 		RETURN_STRING(module->version);
6101 	}
6102 }
6103 /* }}} */
6104 
6105 /* {{{ Returns an array of this extension's functions */
ZEND_METHOD(ReflectionExtension,getFunctions)6106 ZEND_METHOD(ReflectionExtension, getFunctions)
6107 {
6108 	reflection_object *intern;
6109 	zend_module_entry *module;
6110 	zval function;
6111 	zend_function *fptr;
6112 
6113 	if (zend_parse_parameters_none() == FAILURE) {
6114 		RETURN_THROWS();
6115 	}
6116 	GET_REFLECTION_OBJECT_PTR(module);
6117 
6118 	array_init(return_value);
6119 	ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), fptr) {
6120 		if (fptr->common.type==ZEND_INTERNAL_FUNCTION
6121 			&& fptr->internal_function.module == module) {
6122 			reflection_function_factory(fptr, NULL, &function);
6123 			zend_hash_update(Z_ARRVAL_P(return_value), fptr->common.function_name, &function);
6124 		}
6125 	} ZEND_HASH_FOREACH_END();
6126 }
6127 /* }}} */
6128 
6129 /* {{{ Returns an associative array containing this extension's constants and their values */
ZEND_METHOD(ReflectionExtension,getConstants)6130 ZEND_METHOD(ReflectionExtension, getConstants)
6131 {
6132 	reflection_object *intern;
6133 	zend_module_entry *module;
6134 	zend_constant *constant;
6135 
6136 	if (zend_parse_parameters_none() == FAILURE) {
6137 		RETURN_THROWS();
6138 	}
6139 	GET_REFLECTION_OBJECT_PTR(module);
6140 
6141 	array_init(return_value);
6142 	ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
6143 		if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) {
6144 			zval const_val;
6145 			ZVAL_COPY_OR_DUP(&const_val, &constant->value);
6146 			zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val);
6147 		}
6148 	} ZEND_HASH_FOREACH_END();
6149 }
6150 /* }}} */
6151 
6152 /* {{{ _addinientry */
_addinientry(zend_ini_entry * ini_entry,zval * retval,int number)6153 static void _addinientry(zend_ini_entry *ini_entry, zval *retval, int number)
6154 {
6155 	if (number == ini_entry->module_number) {
6156 		zval zv;
6157 		if (ini_entry->value) {
6158 			ZVAL_STR_COPY(&zv, ini_entry->value);
6159 		} else {
6160 			ZVAL_NULL(&zv);
6161 		}
6162 		zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &zv);
6163 	}
6164 }
6165 /* }}} */
6166 
6167 /* {{{ Returns an associative array containing this extension's INI entries and their values */
ZEND_METHOD(ReflectionExtension,getINIEntries)6168 ZEND_METHOD(ReflectionExtension, getINIEntries)
6169 {
6170 	reflection_object *intern;
6171 	zend_module_entry *module;
6172 	zend_ini_entry *ini_entry;
6173 
6174 	if (zend_parse_parameters_none() == FAILURE) {
6175 		RETURN_THROWS();
6176 	}
6177 	GET_REFLECTION_OBJECT_PTR(module);
6178 
6179 	array_init(return_value);
6180 	ZEND_HASH_MAP_FOREACH_PTR(EG(ini_directives), ini_entry) {
6181 		_addinientry(ini_entry, return_value, module->module_number);
6182 	} ZEND_HASH_FOREACH_END();
6183 }
6184 /* }}} */
6185 
6186 /* {{{ add_extension_class */
add_extension_class(zend_class_entry * ce,zend_string * key,zval * class_array,zend_module_entry * module,bool add_reflection_class)6187 static void add_extension_class(zend_class_entry *ce, zend_string *key, zval *class_array, zend_module_entry *module, bool add_reflection_class)
6188 {
6189 	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
6190 		zend_string *name;
6191 
6192 		if (!zend_string_equals_ci(ce->name, key)) {
6193 			/* This is a class alias, use alias name */
6194 			name = key;
6195 		} else {
6196 			/* Use class name */
6197 			name = ce->name;
6198 		}
6199 		if (add_reflection_class) {
6200 			zval zclass;
6201 			zend_reflection_class_factory(ce, &zclass);
6202 			zend_hash_update(Z_ARRVAL_P(class_array), name, &zclass);
6203 		} else {
6204 			add_next_index_str(class_array, zend_string_copy(name));
6205 		}
6206 	}
6207 }
6208 /* }}} */
6209 
6210 /* {{{ Returns an array containing ReflectionClass objects for all classes of this extension */
ZEND_METHOD(ReflectionExtension,getClasses)6211 ZEND_METHOD(ReflectionExtension, getClasses)
6212 {
6213 	reflection_object *intern;
6214 	zend_module_entry *module;
6215 	zend_string *key;
6216 	zend_class_entry *ce;
6217 
6218 	if (zend_parse_parameters_none() == FAILURE) {
6219 		RETURN_THROWS();
6220 	}
6221 	GET_REFLECTION_OBJECT_PTR(module);
6222 
6223 	array_init(return_value);
6224 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
6225 		add_extension_class(ce, key, return_value, module, 1);
6226 	} ZEND_HASH_FOREACH_END();
6227 }
6228 /* }}} */
6229 
6230 /* {{{ Returns an array containing all names of all classes of this extension */
ZEND_METHOD(ReflectionExtension,getClassNames)6231 ZEND_METHOD(ReflectionExtension, getClassNames)
6232 {
6233 	reflection_object *intern;
6234 	zend_module_entry *module;
6235 	zend_string *key;
6236 	zend_class_entry *ce;
6237 
6238 	if (zend_parse_parameters_none() == FAILURE) {
6239 		RETURN_THROWS();
6240 	}
6241 	GET_REFLECTION_OBJECT_PTR(module);
6242 
6243 	array_init(return_value);
6244 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
6245 		add_extension_class(ce, key, return_value, module, 0);
6246 	} ZEND_HASH_FOREACH_END();
6247 }
6248 /* }}} */
6249 
6250 /* {{{ Returns an array containing all names of all extensions this extension depends on */
ZEND_METHOD(ReflectionExtension,getDependencies)6251 ZEND_METHOD(ReflectionExtension, getDependencies)
6252 {
6253 	reflection_object *intern;
6254 	zend_module_entry *module;
6255 	const zend_module_dep *dep;
6256 
6257 	if (zend_parse_parameters_none() == FAILURE) {
6258 		RETURN_THROWS();
6259 	}
6260 	GET_REFLECTION_OBJECT_PTR(module);
6261 
6262 	dep = module->deps;
6263 
6264 	if (!dep)
6265 	{
6266 		RETURN_EMPTY_ARRAY();
6267 	}
6268 
6269 	array_init(return_value);
6270 	while(dep->name) {
6271 		zend_string *relation;
6272 		char *rel_type;
6273 		size_t len = 0;
6274 
6275 		switch(dep->type) {
6276 			case MODULE_DEP_REQUIRED:
6277 				rel_type = "Required";
6278 				len += sizeof("Required") - 1;
6279 				break;
6280 			case MODULE_DEP_CONFLICTS:
6281 				rel_type = "Conflicts";
6282 				len += sizeof("Conflicts") - 1;
6283 				break;
6284 			case MODULE_DEP_OPTIONAL:
6285 				rel_type = "Optional";
6286 				len += sizeof("Optional") - 1;
6287 				break;
6288 			default:
6289 				rel_type = "Error"; /* shouldn't happen */
6290 				len += sizeof("Error") - 1;
6291 				break;
6292 		}
6293 
6294 		if (dep->rel) {
6295 			len += strlen(dep->rel) + 1;
6296 		}
6297 
6298 		if (dep->version) {
6299 			len += strlen(dep->version) + 1;
6300 		}
6301 
6302 		relation = zend_string_alloc(len, 0);
6303 		snprintf(ZSTR_VAL(relation), ZSTR_LEN(relation) + 1, "%s%s%s%s%s",
6304 						rel_type,
6305 						dep->rel ? " " : "",
6306 						dep->rel ? dep->rel : "",
6307 						dep->version ? " " : "",
6308 						dep->version ? dep->version : "");
6309 		add_assoc_str(return_value, dep->name, relation);
6310 		dep++;
6311 	}
6312 }
6313 /* }}} */
6314 
6315 /* {{{ Prints phpinfo block for the extension */
ZEND_METHOD(ReflectionExtension,info)6316 ZEND_METHOD(ReflectionExtension, info)
6317 {
6318 	reflection_object *intern;
6319 	zend_module_entry *module;
6320 
6321 	if (zend_parse_parameters_none() == FAILURE) {
6322 		RETURN_THROWS();
6323 	}
6324 	GET_REFLECTION_OBJECT_PTR(module);
6325 
6326 	php_info_print_module(module);
6327 }
6328 /* }}} */
6329 
6330 /* {{{ Returns whether this extension is persistent */
ZEND_METHOD(ReflectionExtension,isPersistent)6331 ZEND_METHOD(ReflectionExtension, isPersistent)
6332 {
6333 	reflection_object *intern;
6334 	zend_module_entry *module;
6335 
6336 	if (zend_parse_parameters_none() == FAILURE) {
6337 		RETURN_THROWS();
6338 	}
6339 	GET_REFLECTION_OBJECT_PTR(module);
6340 
6341 	RETURN_BOOL(module->type == MODULE_PERSISTENT);
6342 }
6343 /* }}} */
6344 
6345 /* {{{ Returns whether this extension is temporary */
ZEND_METHOD(ReflectionExtension,isTemporary)6346 ZEND_METHOD(ReflectionExtension, isTemporary)
6347 {
6348 	reflection_object *intern;
6349 	zend_module_entry *module;
6350 
6351 	if (zend_parse_parameters_none() == FAILURE) {
6352 		RETURN_THROWS();
6353 	}
6354 	GET_REFLECTION_OBJECT_PTR(module);
6355 
6356 	RETURN_BOOL(module->type == MODULE_TEMPORARY);
6357 }
6358 /* }}} */
6359 
6360 /* {{{ Constructor. Throws an Exception in case the given Zend extension does not exist */
ZEND_METHOD(ReflectionZendExtension,__construct)6361 ZEND_METHOD(ReflectionZendExtension, __construct)
6362 {
6363 	zval *object;
6364 	reflection_object *intern;
6365 	zend_extension *extension;
6366 	char *name_str;
6367 	size_t name_len;
6368 
6369 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
6370 		RETURN_THROWS();
6371 	}
6372 
6373 	object = ZEND_THIS;
6374 	intern = Z_REFLECTION_P(object);
6375 
6376 	extension = zend_get_extension(name_str);
6377 	if (!extension) {
6378 		zend_throw_exception_ex(reflection_exception_ptr, 0,
6379 				"Zend Extension \"%s\" does not exist", name_str);
6380 		RETURN_THROWS();
6381 	}
6382 	ZVAL_STRING(reflection_prop_name(object), extension->name);
6383 	intern->ptr = extension;
6384 	intern->ref_type = REF_TYPE_OTHER;
6385 	intern->ce = NULL;
6386 }
6387 /* }}} */
6388 
6389 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionZendExtension,__toString)6390 ZEND_METHOD(ReflectionZendExtension, __toString)
6391 {
6392 	reflection_object *intern;
6393 	zend_extension *extension;
6394 	smart_str str = {0};
6395 
6396 	if (zend_parse_parameters_none() == FAILURE) {
6397 		RETURN_THROWS();
6398 	}
6399 	GET_REFLECTION_OBJECT_PTR(extension);
6400 	_zend_extension_string(&str, extension, "");
6401 	RETURN_STR(smart_str_extract(&str));
6402 }
6403 /* }}} */
6404 
6405 /* {{{ Returns the name of this Zend extension */
ZEND_METHOD(ReflectionZendExtension,getName)6406 ZEND_METHOD(ReflectionZendExtension, getName)
6407 {
6408 	reflection_object *intern;
6409 	zend_extension *extension;
6410 
6411 	if (zend_parse_parameters_none() == FAILURE) {
6412 		RETURN_THROWS();
6413 	}
6414 	GET_REFLECTION_OBJECT_PTR(extension);
6415 
6416 	RETURN_STRING(extension->name);
6417 }
6418 /* }}} */
6419 
6420 /* {{{ Returns the version information of this Zend extension */
ZEND_METHOD(ReflectionZendExtension,getVersion)6421 ZEND_METHOD(ReflectionZendExtension, getVersion)
6422 {
6423 	reflection_object *intern;
6424 	zend_extension *extension;
6425 
6426 	if (zend_parse_parameters_none() == FAILURE) {
6427 		RETURN_THROWS();
6428 	}
6429 	GET_REFLECTION_OBJECT_PTR(extension);
6430 
6431 	if (extension->version) {
6432 		RETURN_STRING(extension->version);
6433 	} else {
6434 		RETURN_EMPTY_STRING();
6435 	}
6436 }
6437 /* }}} */
6438 
6439 /* {{{ Returns the name of this Zend extension's author */
ZEND_METHOD(ReflectionZendExtension,getAuthor)6440 ZEND_METHOD(ReflectionZendExtension, getAuthor)
6441 {
6442 	reflection_object *intern;
6443 	zend_extension *extension;
6444 
6445 	if (zend_parse_parameters_none() == FAILURE) {
6446 		RETURN_THROWS();
6447 	}
6448 	GET_REFLECTION_OBJECT_PTR(extension);
6449 
6450 	if (extension->author) {
6451 		RETURN_STRING(extension->author);
6452 	} else {
6453 		RETURN_EMPTY_STRING();
6454 	}
6455 }
6456 /* }}} */
6457 
6458 /* {{{ Returns this Zend extension's URL*/
ZEND_METHOD(ReflectionZendExtension,getURL)6459 ZEND_METHOD(ReflectionZendExtension, getURL)
6460 {
6461 	reflection_object *intern;
6462 	zend_extension *extension;
6463 
6464 	if (zend_parse_parameters_none() == FAILURE) {
6465 		RETURN_THROWS();
6466 	}
6467 	GET_REFLECTION_OBJECT_PTR(extension);
6468 
6469 	if (extension->URL) {
6470 		RETURN_STRING(extension->URL);
6471 	} else {
6472 		RETURN_EMPTY_STRING();
6473 	}
6474 }
6475 /* }}} */
6476 
6477 /* {{{ Returns this Zend extension's copyright information */
ZEND_METHOD(ReflectionZendExtension,getCopyright)6478 ZEND_METHOD(ReflectionZendExtension, getCopyright)
6479 {
6480 	reflection_object *intern;
6481 	zend_extension *extension;
6482 
6483 	if (zend_parse_parameters_none() == FAILURE) {
6484 		RETURN_THROWS();
6485 	}
6486 	GET_REFLECTION_OBJECT_PTR(extension);
6487 
6488 	if (extension->copyright) {
6489 		RETURN_STRING(extension->copyright);
6490 	} else {
6491 		RETURN_EMPTY_STRING();
6492 	}
6493 }
6494 /* }}} */
6495 
6496 /* {{{     Dummy constructor -- always throws ReflectionExceptions. */
ZEND_METHOD(ReflectionReference,__construct)6497 ZEND_METHOD(ReflectionReference, __construct)
6498 {
6499 	_DO_THROW(
6500 		"Cannot directly instantiate ReflectionReference. "
6501 		"Use ReflectionReference::fromArrayElement() instead"
6502 	);
6503 }
6504 /* }}} */
6505 
is_ignorable_reference(HashTable * ht,zval * ref)6506 static bool is_ignorable_reference(HashTable *ht, zval *ref) {
6507 	if (Z_REFCOUNT_P(ref) != 1) {
6508 		return 0;
6509 	}
6510 
6511 	/* Directly self-referential arrays are treated as proper references
6512 	 * in zend_array_dup() despite rc=1. */
6513 	return Z_TYPE_P(Z_REFVAL_P(ref)) != IS_ARRAY || Z_ARRVAL_P(Z_REFVAL_P(ref)) != ht;
6514 }
6515 
6516 /* {{{     Create ReflectionReference for array item. Returns null if not a reference. */
ZEND_METHOD(ReflectionReference,fromArrayElement)6517 ZEND_METHOD(ReflectionReference, fromArrayElement)
6518 {
6519 	HashTable *ht;
6520 	zval *item;
6521 	zend_string *string_key = NULL;
6522 	zend_long int_key = 0;
6523 	reflection_object *intern;
6524 
6525 	ZEND_PARSE_PARAMETERS_START(2, 2)
6526 		Z_PARAM_ARRAY_HT(ht)
6527 		Z_PARAM_STR_OR_LONG(string_key, int_key)
6528 	ZEND_PARSE_PARAMETERS_END();
6529 
6530 	if (string_key) {
6531 		item = zend_hash_find(ht, string_key);
6532 	} else {
6533 		item = zend_hash_index_find(ht, int_key);
6534 	}
6535 
6536 	if (!item) {
6537 		_DO_THROW("Array key not found");
6538 		RETURN_THROWS();
6539 	}
6540 
6541 	if (Z_TYPE_P(item) != IS_REFERENCE || is_ignorable_reference(ht, item)) {
6542 		RETURN_NULL();
6543 	}
6544 
6545 	object_init_ex(return_value, reflection_reference_ptr);
6546 	intern = Z_REFLECTION_P(return_value);
6547 	ZVAL_COPY(&intern->obj, item);
6548 	intern->ref_type = REF_TYPE_OTHER;
6549 }
6550 /* }}} */
6551 
6552 /* {{{     Returns a unique identifier for the reference.
6553  *     The format of the return value is unspecified and may change. */
ZEND_METHOD(ReflectionReference,getId)6554 ZEND_METHOD(ReflectionReference, getId)
6555 {
6556 	reflection_object *intern;
6557 	unsigned char digest[20];
6558 	PHP_SHA1_CTX context;
6559 
6560 	if (zend_parse_parameters_none() == FAILURE) {
6561 		RETURN_THROWS();
6562 	}
6563 
6564 	intern = Z_REFLECTION_P(ZEND_THIS);
6565 	if (Z_TYPE(intern->obj) != IS_REFERENCE) {
6566 		_DO_THROW("Corrupted ReflectionReference object");
6567 		RETURN_THROWS();
6568 	}
6569 
6570 	if (!REFLECTION_G(key_initialized)) {
6571 		if (php_random_bytes_throw(&REFLECTION_G(key), 16) == FAILURE) {
6572 			RETURN_THROWS();
6573 		}
6574 
6575 		REFLECTION_G(key_initialized) = 1;
6576 	}
6577 
6578 	/* SHA1(ref || key) to avoid directly exposing memory addresses. */
6579 	PHP_SHA1Init(&context);
6580 	PHP_SHA1Update(&context, (unsigned char *) &Z_REF(intern->obj), sizeof(zend_reference *));
6581 	PHP_SHA1Update(&context, REFLECTION_G(key), REFLECTION_KEY_LEN);
6582 	PHP_SHA1Final(digest, &context);
6583 
6584 	RETURN_STRINGL((char *) digest, sizeof(digest));
6585 }
6586 /* }}} */
6587 
ZEND_METHOD(ReflectionAttribute,__construct)6588 ZEND_METHOD(ReflectionAttribute, __construct)
6589 {
6590 	_DO_THROW("Cannot directly instantiate ReflectionAttribute");
6591 }
6592 
ZEND_METHOD(ReflectionAttribute,__clone)6593 ZEND_METHOD(ReflectionAttribute, __clone)
6594 {
6595 	/* Should never be executable */
6596 	_DO_THROW("Cannot clone object using __clone()");
6597 }
6598 
6599 /* {{{ Returns a string representation */
ZEND_METHOD(ReflectionAttribute,__toString)6600 ZEND_METHOD(ReflectionAttribute, __toString)
6601 {
6602 	reflection_object *intern;
6603 	attribute_reference *attr;
6604 
6605 	if (zend_parse_parameters_none() == FAILURE) {
6606 		RETURN_THROWS();
6607 	}
6608 
6609 	GET_REFLECTION_OBJECT_PTR(attr);
6610 
6611 	smart_str str = {0};
6612 	smart_str_appends(&str, "Attribute [ ");
6613 	smart_str_append(&str, attr->data->name);
6614 	smart_str_appends(&str, " ]");
6615 
6616 	if (attr->data->argc > 0) {
6617 		smart_str_appends(&str, " {\n");
6618 		smart_str_append_printf(&str, "  - Arguments [%d] {\n", attr->data->argc);
6619 
6620 		for (uint32_t i = 0; i < attr->data->argc; i++) {
6621 			smart_str_append_printf(&str, "    Argument #%d [ ", i);
6622 			if (attr->data->args[i].name != NULL) {
6623 				smart_str_append(&str, attr->data->args[i].name);
6624 				smart_str_appends(&str, " = ");
6625 			}
6626 
6627 			if (format_default_value(&str, &attr->data->args[i].value) == FAILURE) {
6628 				smart_str_free(&str);
6629 				RETURN_THROWS();
6630 			}
6631 
6632 			smart_str_appends(&str, " ]\n");
6633 		}
6634 		smart_str_appends(&str, "  }\n");
6635 
6636 		smart_str_appends(&str, "}\n");
6637 	} else {
6638 		smart_str_appendc(&str, '\n');
6639 	}
6640 
6641 	RETURN_STR(smart_str_extract(&str));
6642 }
6643 /* }}} */
6644 
6645 /* {{{ Returns the name of the attribute */
ZEND_METHOD(ReflectionAttribute,getName)6646 ZEND_METHOD(ReflectionAttribute, getName)
6647 {
6648 	reflection_object *intern;
6649 	attribute_reference *attr;
6650 
6651 	if (zend_parse_parameters_none() == FAILURE) {
6652 		RETURN_THROWS();
6653 	}
6654 	GET_REFLECTION_OBJECT_PTR(attr);
6655 
6656 	RETURN_STR_COPY(attr->data->name);
6657 }
6658 /* }}} */
6659 
6660 /* {{{ Returns the target of the attribute */
ZEND_METHOD(ReflectionAttribute,getTarget)6661 ZEND_METHOD(ReflectionAttribute, getTarget)
6662 {
6663 	reflection_object *intern;
6664 	attribute_reference *attr;
6665 
6666 	if (zend_parse_parameters_none() == FAILURE) {
6667 		RETURN_THROWS();
6668 	}
6669 	GET_REFLECTION_OBJECT_PTR(attr);
6670 
6671 	RETURN_LONG(attr->target);
6672 }
6673 /* }}} */
6674 
6675 /* {{{ Returns true if the attribute is repeated */
ZEND_METHOD(ReflectionAttribute,isRepeated)6676 ZEND_METHOD(ReflectionAttribute, isRepeated)
6677 {
6678 	reflection_object *intern;
6679 	attribute_reference *attr;
6680 
6681 	if (zend_parse_parameters_none() == FAILURE) {
6682 		RETURN_THROWS();
6683 	}
6684 	GET_REFLECTION_OBJECT_PTR(attr);
6685 
6686 	RETURN_BOOL(zend_is_attribute_repeated(attr->attributes, attr->data));
6687 }
6688 /* }}} */
6689 
6690 /* {{{ Returns the arguments passed to the attribute */
ZEND_METHOD(ReflectionAttribute,getArguments)6691 ZEND_METHOD(ReflectionAttribute, getArguments)
6692 {
6693 	reflection_object *intern;
6694 	attribute_reference *attr;
6695 
6696 	zval tmp;
6697 	uint32_t i;
6698 
6699 	if (zend_parse_parameters_none() == FAILURE) {
6700 		RETURN_THROWS();
6701 	}
6702 	GET_REFLECTION_OBJECT_PTR(attr);
6703 
6704 	array_init(return_value);
6705 
6706 	for (i = 0; i < attr->data->argc; i++) {
6707 		if (FAILURE == zend_get_attribute_value(&tmp, attr->data, i, attr->scope)) {
6708 			RETURN_THROWS();
6709 		}
6710 
6711 		if (attr->data->args[i].name) {
6712 			/* We ensured at compile-time that there are no duplicate parameter names. */
6713 			zend_hash_add_new(Z_ARRVAL_P(return_value), attr->data->args[i].name, &tmp);
6714 		} else {
6715 			add_next_index_zval(return_value, &tmp);
6716 		}
6717 	}
6718 }
6719 /* }}} */
6720 
6721 /* {{{ Returns the attribute as an object */
ZEND_METHOD(ReflectionAttribute,newInstance)6722 ZEND_METHOD(ReflectionAttribute, newInstance)
6723 {
6724 	reflection_object *intern;
6725 	attribute_reference *attr;
6726 	zend_attribute *marker;
6727 
6728 	zend_class_entry *ce;
6729 
6730 	if (zend_parse_parameters_none() == FAILURE) {
6731 		RETURN_THROWS();
6732 	}
6733 
6734 	GET_REFLECTION_OBJECT_PTR(attr);
6735 
6736 	if (NULL == (ce = zend_lookup_class(attr->data->name))) {
6737 		zend_throw_error(NULL, "Attribute class \"%s\" not found", ZSTR_VAL(attr->data->name));
6738 		RETURN_THROWS();
6739 	}
6740 
6741 	if (NULL == (marker = zend_get_attribute_str(ce->attributes, ZEND_STRL("attribute")))) {
6742 		zend_throw_error(NULL, "Attempting to use non-attribute class \"%s\" as attribute", ZSTR_VAL(attr->data->name));
6743 		RETURN_THROWS();
6744 	}
6745 
6746 	if (ce->type == ZEND_USER_CLASS) {
6747 		uint32_t flags = zend_attribute_attribute_get_flags(marker, ce);
6748 		if (EG(exception)) {
6749 			RETURN_THROWS();
6750 		}
6751 
6752 		if (!(attr->target & flags)) {
6753 			zend_string *location = zend_get_attribute_target_names(attr->target);
6754 			zend_string *allowed = zend_get_attribute_target_names(flags);
6755 
6756 			zend_throw_error(NULL, "Attribute \"%s\" cannot target %s (allowed targets: %s)",
6757 				ZSTR_VAL(attr->data->name), ZSTR_VAL(location), ZSTR_VAL(allowed)
6758 			);
6759 
6760 			zend_string_release(location);
6761 			zend_string_release(allowed);
6762 
6763 			RETURN_THROWS();
6764 		}
6765 
6766 		if (!(flags & ZEND_ATTRIBUTE_IS_REPEATABLE)) {
6767 			if (zend_is_attribute_repeated(attr->attributes, attr->data)) {
6768 				zend_throw_error(NULL, "Attribute \"%s\" must not be repeated", ZSTR_VAL(attr->data->name));
6769 				RETURN_THROWS();
6770 			}
6771 		}
6772 	}
6773 
6774 	zval obj;
6775 
6776 	if (SUCCESS != zend_get_attribute_object(&obj, ce, attr->data, attr->scope, attr->filename)) {
6777 		RETURN_THROWS();
6778 	}
6779 
6780 	RETURN_COPY_VALUE(&obj);
6781 }
6782 
ZEND_METHOD(ReflectionEnum,__construct)6783 ZEND_METHOD(ReflectionEnum, __construct)
6784 {
6785 	reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
6786 	if (EG(exception)) {
6787 		RETURN_THROWS();
6788 	}
6789 
6790 	reflection_object *intern;
6791 	zend_class_entry *ce;
6792 	GET_REFLECTION_OBJECT_PTR(ce);
6793 
6794 	if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
6795 		zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" is not an enum", ZSTR_VAL(ce->name));
6796 		RETURN_THROWS();
6797 	}
6798 }
6799 
ZEND_METHOD(ReflectionEnum,hasCase)6800 ZEND_METHOD(ReflectionEnum, hasCase)
6801 {
6802 	reflection_object *intern;
6803 	zend_class_entry *ce;
6804 	zend_string *name;
6805 
6806 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
6807 		RETURN_THROWS();
6808 	}
6809 
6810 	GET_REFLECTION_OBJECT_PTR(ce);
6811 
6812 	zend_class_constant *class_const = zend_hash_find_ptr(&ce->constants_table, name);
6813 	if (class_const == NULL) {
6814 		RETURN_FALSE;
6815 	}
6816 
6817 	RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(class_const) & ZEND_CLASS_CONST_IS_CASE);
6818 }
6819 
ZEND_METHOD(ReflectionEnum,getCase)6820 ZEND_METHOD(ReflectionEnum, getCase)
6821 {
6822 	reflection_object *intern;
6823 	zend_class_entry *ce;
6824 	zend_string *name;
6825 
6826 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
6827 		RETURN_THROWS();
6828 	}
6829 
6830 	GET_REFLECTION_OBJECT_PTR(ce);
6831 
6832 	zend_class_constant *constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name);
6833 	if (constant == NULL) {
6834 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Case %s::%s does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
6835 		RETURN_THROWS();
6836 	}
6837 	if (!(ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE)) {
6838 		zend_throw_exception_ex(reflection_exception_ptr, 0, "%s::%s is not a case", ZSTR_VAL(ce->name), ZSTR_VAL(name));
6839 		RETURN_THROWS();
6840 	}
6841 
6842 	reflection_enum_case_factory(ce, name, constant, return_value);
6843 }
6844 
ZEND_METHOD(ReflectionEnum,getCases)6845 ZEND_METHOD(ReflectionEnum, getCases)
6846 {
6847 	reflection_object *intern;
6848 	zend_class_entry *ce;
6849 	zend_string *name;
6850 	zend_class_constant *constant;
6851 
6852 	if (zend_parse_parameters_none() == FAILURE) {
6853 		RETURN_THROWS();
6854 	}
6855 
6856 	GET_REFLECTION_OBJECT_PTR(ce);
6857 
6858 	array_init(return_value);
6859 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), name, constant) {
6860 		if (ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE) {
6861 			zval class_const;
6862 			reflection_enum_case_factory(ce, name, constant, &class_const);
6863 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &class_const);
6864 		}
6865 	} ZEND_HASH_FOREACH_END();
6866 }
6867 
ZEND_METHOD(ReflectionEnum,isBacked)6868 ZEND_METHOD(ReflectionEnum, isBacked)
6869 {
6870 	reflection_object *intern;
6871 	zend_class_entry *ce;
6872 
6873 	if (zend_parse_parameters_none() == FAILURE) {
6874 		RETURN_THROWS();
6875 	}
6876 
6877 	GET_REFLECTION_OBJECT_PTR(ce);
6878 	RETURN_BOOL(ce->enum_backing_type != IS_UNDEF);
6879 }
6880 
ZEND_METHOD(ReflectionEnum,getBackingType)6881 ZEND_METHOD(ReflectionEnum, getBackingType)
6882 {
6883 	reflection_object *intern;
6884 	zend_class_entry *ce;
6885 
6886 	if (zend_parse_parameters_none() == FAILURE) {
6887 		RETURN_THROWS();
6888 	}
6889 
6890 	GET_REFLECTION_OBJECT_PTR(ce);
6891 
6892 	if (ce->enum_backing_type == IS_UNDEF) {
6893 		RETURN_NULL();
6894 	} else {
6895 		zend_type type = ZEND_TYPE_INIT_CODE(ce->enum_backing_type, 0, 0);
6896 		reflection_type_factory(type, return_value, 0);
6897 	}
6898 }
6899 
ZEND_METHOD(ReflectionEnumUnitCase,__construct)6900 ZEND_METHOD(ReflectionEnumUnitCase, __construct)
6901 {
6902 	ZEND_MN(ReflectionClassConstant___construct)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
6903 	if (EG(exception)) {
6904 		RETURN_THROWS();
6905 	}
6906 
6907 	reflection_object *intern;
6908 	zend_class_constant *ref;
6909 
6910 	GET_REFLECTION_OBJECT_PTR(ref);
6911 
6912 	if (!(ZEND_CLASS_CONST_FLAGS(ref) & ZEND_CLASS_CONST_IS_CASE)) {
6913 		zval *case_name = reflection_prop_name(ZEND_THIS);
6914 		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));
6915 		RETURN_THROWS();
6916 	}
6917 }
6918 
ZEND_METHOD(ReflectionEnumUnitCase,getEnum)6919 ZEND_METHOD(ReflectionEnumUnitCase, getEnum)
6920 {
6921 	reflection_object *intern;
6922 	zend_class_constant *ref;
6923 
6924 	if (zend_parse_parameters_none() == FAILURE) {
6925 		RETURN_THROWS();
6926 	}
6927 	GET_REFLECTION_OBJECT_PTR(ref);
6928 
6929 	zend_reflection_class_factory(ref->ce, return_value);
6930 }
6931 
ZEND_METHOD(ReflectionEnumBackedCase,__construct)6932 ZEND_METHOD(ReflectionEnumBackedCase, __construct)
6933 {
6934 	ZEND_MN(ReflectionEnumUnitCase___construct)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
6935 	if (EG(exception)) {
6936 		RETURN_THROWS();
6937 	}
6938 
6939 	reflection_object *intern;
6940 	zend_class_constant *ref;
6941 
6942 	GET_REFLECTION_OBJECT_PTR(ref);
6943 
6944 	if (ref->ce->enum_backing_type == IS_UNDEF) {
6945 		zval *case_name = reflection_prop_name(ZEND_THIS);
6946 		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));
6947 		RETURN_THROWS();
6948 	}
6949 }
6950 
ZEND_METHOD(ReflectionEnumBackedCase,getBackingValue)6951 ZEND_METHOD(ReflectionEnumBackedCase, getBackingValue)
6952 {
6953 	reflection_object *intern;
6954 	zend_class_constant *ref;
6955 
6956 	if (zend_parse_parameters_none() == FAILURE) {
6957 		RETURN_THROWS();
6958 	}
6959 	GET_REFLECTION_OBJECT_PTR(ref);
6960 
6961 	if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
6962 		zval_update_constant_ex(&ref->value, ref->ce);
6963 		if (EG(exception)) {
6964 			RETURN_THROWS();
6965 		}
6966 	}
6967 
6968 	ZEND_ASSERT(intern->ce->enum_backing_type != IS_UNDEF);
6969 	zval *member_p = zend_enum_fetch_case_value(Z_OBJ(ref->value));
6970 
6971 	ZVAL_COPY_OR_DUP(return_value, member_p);
6972 }
6973 
6974 /* {{{ proto ReflectionFiber::__construct(Fiber $fiber) */
ZEND_METHOD(ReflectionFiber,__construct)6975 ZEND_METHOD(ReflectionFiber, __construct)
6976 {
6977 	zval *fiber, *object;
6978 	reflection_object *intern;
6979 
6980 	object = ZEND_THIS;
6981 	intern = Z_REFLECTION_P(object);
6982 
6983 	ZEND_PARSE_PARAMETERS_START(1, 1)
6984 		Z_PARAM_OBJECT_OF_CLASS(fiber, zend_ce_fiber)
6985 	ZEND_PARSE_PARAMETERS_END();
6986 
6987 	if (intern->ce) {
6988 		zval_ptr_dtor(&intern->obj);
6989 	}
6990 
6991 	intern->ref_type = REF_TYPE_FIBER;
6992 	ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(fiber));
6993 	intern->ce = zend_ce_fiber;
6994 }
6995 /* }}} */
6996 
ZEND_METHOD(ReflectionFiber,getFiber)6997 ZEND_METHOD(ReflectionFiber, getFiber)
6998 {
6999 	ZEND_PARSE_PARAMETERS_NONE();
7000 
7001 	RETURN_OBJ_COPY(Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj));
7002 }
7003 
7004 #define REFLECTION_CHECK_VALID_FIBER(fiber) do { \
7005 		if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_INIT || fiber->context.status == ZEND_FIBER_STATUS_DEAD) { \
7006 			zend_throw_error(NULL, "Cannot fetch information from a fiber that has not been started or is terminated"); \
7007 			RETURN_THROWS(); \
7008 		} \
7009 	} while (0)
7010 
ZEND_METHOD(ReflectionFiber,getTrace)7011 ZEND_METHOD(ReflectionFiber, getTrace)
7012 {
7013 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7014 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
7015 	zend_execute_data *prev_execute_data;
7016 
7017 	ZEND_PARSE_PARAMETERS_START(0, 1)
7018 		Z_PARAM_OPTIONAL
7019 		Z_PARAM_LONG(options);
7020 	ZEND_PARSE_PARAMETERS_END();
7021 
7022 	REFLECTION_CHECK_VALID_FIBER(fiber);
7023 
7024 	prev_execute_data = fiber->stack_bottom->prev_execute_data;
7025 	fiber->stack_bottom->prev_execute_data = NULL;
7026 
7027 	if (EG(active_fiber) != fiber) {
7028 		// No need to replace current execute data if within the current fiber.
7029 		EG(current_execute_data) = fiber->execute_data;
7030 	}
7031 
7032 	zend_fetch_debug_backtrace(return_value, 0, options, 0);
7033 
7034 	EG(current_execute_data) = execute_data; // Restore original execute data.
7035 	fiber->stack_bottom->prev_execute_data = prev_execute_data; // Restore prev execute data on fiber stack.
7036 }
7037 
ZEND_METHOD(ReflectionFiber,getExecutingLine)7038 ZEND_METHOD(ReflectionFiber, getExecutingLine)
7039 {
7040 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7041 	zend_execute_data *prev_execute_data;
7042 
7043 	ZEND_PARSE_PARAMETERS_NONE();
7044 
7045 	REFLECTION_CHECK_VALID_FIBER(fiber);
7046 
7047 	if (EG(active_fiber) == fiber) {
7048 		prev_execute_data = execute_data->prev_execute_data;
7049 	} else {
7050 		prev_execute_data = fiber->execute_data->prev_execute_data;
7051 	}
7052 
7053 	while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) {
7054 		prev_execute_data = prev_execute_data->prev_execute_data;
7055 	}
7056 	if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
7057 		RETURN_LONG(prev_execute_data->opline->lineno);
7058 	}
7059 	RETURN_NULL();
7060 }
7061 
ZEND_METHOD(ReflectionFiber,getExecutingFile)7062 ZEND_METHOD(ReflectionFiber, getExecutingFile)
7063 {
7064 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7065 	zend_execute_data *prev_execute_data;
7066 
7067 	ZEND_PARSE_PARAMETERS_NONE();
7068 
7069 	REFLECTION_CHECK_VALID_FIBER(fiber);
7070 
7071 	if (EG(active_fiber) == fiber) {
7072 		prev_execute_data = execute_data->prev_execute_data;
7073 	} else {
7074 		prev_execute_data = fiber->execute_data->prev_execute_data;
7075 	}
7076 
7077 	while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) {
7078 		prev_execute_data = prev_execute_data->prev_execute_data;
7079 	}
7080 	if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
7081 		RETURN_STR_COPY(prev_execute_data->func->op_array.filename);
7082 	}
7083 	RETURN_NULL();
7084 }
7085 
ZEND_METHOD(ReflectionFiber,getCallable)7086 ZEND_METHOD(ReflectionFiber, getCallable)
7087 {
7088 	zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7089 
7090 	ZEND_PARSE_PARAMETERS_NONE();
7091 
7092 	if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
7093 		zend_throw_error(NULL, "Cannot fetch the callable from a fiber that has terminated"); \
7094 		RETURN_THROWS();
7095 	}
7096 
7097 	RETURN_COPY(&fiber->fci.function_name);
7098 }
7099 
7100 /* {{{ _reflection_write_property */
_reflection_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)7101 static zval *_reflection_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
7102 {
7103 	if (zend_hash_exists(&object->ce->properties_info, name)
7104 		&& (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_NAME)) || zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_CLASS))))
7105 	{
7106 		zend_throw_exception_ex(reflection_exception_ptr, 0,
7107 			"Cannot set read-only property %s::$%s", ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
7108 		return &EG(uninitialized_zval);
7109 	}
7110 	else
7111 	{
7112 		return zend_std_write_property(object, name, value, cache_slot);
7113 	}
7114 }
7115 /* }}} */
7116 
ZEND_METHOD(ReflectionConstant,__construct)7117 ZEND_METHOD(ReflectionConstant, __construct)
7118 {
7119 	zend_string *name;
7120 
7121 	zval *object = ZEND_THIS;
7122 	reflection_object *intern = Z_REFLECTION_P(object);
7123 
7124 	ZEND_PARSE_PARAMETERS_START(1, 1)
7125 		Z_PARAM_STR(name)
7126 	ZEND_PARSE_PARAMETERS_END();
7127 
7128 	/* Build name with lowercased ns. */
7129 	bool backslash_prefixed = ZSTR_VAL(name)[0] == '\\';
7130 	char *source = ZSTR_VAL(name) + backslash_prefixed;
7131 	size_t source_len = ZSTR_LEN(name) - backslash_prefixed;
7132 	zend_string *lc_name = zend_string_alloc(source_len, /* persistent */ false);
7133 	const char *ns_end = zend_memrchr(source, '\\', source_len);
7134 	size_t ns_len = 0;
7135 	if (ns_end) {
7136 		ns_len = ns_end - ZSTR_VAL(name);
7137 		zend_str_tolower_copy(ZSTR_VAL(lc_name), source, ns_len);
7138 	}
7139 	memcpy(ZSTR_VAL(lc_name) + ns_len, source + ns_len, source_len - ns_len);
7140 
7141 	zend_constant *const_ = zend_get_constant_ptr(lc_name);
7142 	zend_string_release_ex(lc_name, /* persistent */ false);
7143 	if (!const_) {
7144 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant \"%s\" does not exist", ZSTR_VAL(name));
7145 		RETURN_THROWS();
7146 	}
7147 
7148 	intern->ptr = const_;
7149 	intern->ref_type = REF_TYPE_OTHER;
7150 
7151 	zval *name_zv = reflection_prop_name(object);
7152 	zval_ptr_dtor(name_zv);
7153 	ZVAL_STR_COPY(name_zv, name);
7154 }
7155 
ZEND_METHOD(ReflectionConstant,getName)7156 ZEND_METHOD(ReflectionConstant, getName)
7157 {
7158 	reflection_object *intern;
7159 	zend_constant *const_;
7160 
7161 	if (zend_parse_parameters_none() == FAILURE) {
7162 		RETURN_THROWS();
7163 	}
7164 
7165 	GET_REFLECTION_OBJECT_PTR(const_);
7166 	RETURN_STR_COPY(const_->name);
7167 }
7168 
ZEND_METHOD(ReflectionConstant,getNamespaceName)7169 ZEND_METHOD(ReflectionConstant, getNamespaceName)
7170 {
7171 	reflection_object *intern;
7172 	zend_constant *const_;
7173 
7174 	if (zend_parse_parameters_none() == FAILURE) {
7175 		RETURN_THROWS();
7176 	}
7177 
7178 	GET_REFLECTION_OBJECT_PTR(const_);
7179 
7180 	const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
7181 	if (backslash) {
7182 		size_t length = backslash - ZSTR_VAL(const_->name);
7183 		RETURN_STRINGL(ZSTR_VAL(const_->name), length);
7184 	} else {
7185 		RETURN_EMPTY_STRING();
7186 	}
7187 }
7188 
ZEND_METHOD(ReflectionConstant,getShortName)7189 ZEND_METHOD(ReflectionConstant, getShortName)
7190 {
7191 	reflection_object *intern;
7192 	zend_constant *const_;
7193 
7194 	if (zend_parse_parameters_none() == FAILURE) {
7195 		RETURN_THROWS();
7196 	}
7197 
7198 	GET_REFLECTION_OBJECT_PTR(const_);
7199 
7200 	const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
7201 	if (backslash) {
7202 		size_t prefix = backslash - ZSTR_VAL(const_->name) + 1;
7203 		size_t length = ZSTR_LEN(const_->name) - prefix;
7204 		RETURN_STRINGL(ZSTR_VAL(const_->name) + prefix, length);
7205 	} else {
7206 		RETURN_STR_COPY(const_->name);
7207 	}
7208 }
7209 
ZEND_METHOD(ReflectionConstant,getValue)7210 ZEND_METHOD(ReflectionConstant, getValue)
7211 {
7212 	reflection_object *intern;
7213 	zend_constant *const_;
7214 
7215 	if (zend_parse_parameters_none() == FAILURE) {
7216 		RETURN_THROWS();
7217 	}
7218 
7219 	GET_REFLECTION_OBJECT_PTR(const_);
7220 	RETURN_COPY(&const_->value);
7221 }
7222 
ZEND_METHOD(ReflectionConstant,isDeprecated)7223 ZEND_METHOD(ReflectionConstant, isDeprecated)
7224 {
7225 	reflection_object *intern;
7226 	zend_constant *const_;
7227 
7228 	if (zend_parse_parameters_none() == FAILURE) {
7229 		RETURN_THROWS();
7230 	}
7231 
7232 	GET_REFLECTION_OBJECT_PTR(const_);
7233 	RETURN_BOOL(ZEND_CONSTANT_FLAGS(const_) & CONST_DEPRECATED);
7234 }
7235 
ZEND_METHOD(ReflectionConstant,__toString)7236 ZEND_METHOD(ReflectionConstant, __toString)
7237 {
7238 	reflection_object *intern;
7239 	zend_constant *const_;
7240 	smart_str str = {0};
7241 
7242 	if (zend_parse_parameters_none() == FAILURE) {
7243 		RETURN_THROWS();
7244 	}
7245 
7246 	GET_REFLECTION_OBJECT_PTR(const_);
7247 	_const_string(&str, ZSTR_VAL(const_->name), &const_->value, "");
7248 	RETURN_STR(smart_str_extract(&str));
7249 }
7250 
PHP_MINIT_FUNCTION(reflection)7251 PHP_MINIT_FUNCTION(reflection) /* {{{ */
7252 {
7253 	memcpy(&reflection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
7254 	reflection_object_handlers.offset = XtOffsetOf(reflection_object, zo);
7255 	reflection_object_handlers.free_obj = reflection_free_objects_storage;
7256 	reflection_object_handlers.clone_obj = NULL;
7257 	reflection_object_handlers.write_property = _reflection_write_property;
7258 	reflection_object_handlers.get_gc = reflection_get_gc;
7259 
7260 	reflection_exception_ptr = register_class_ReflectionException(zend_ce_exception);
7261 
7262 	reflection_ptr = register_class_Reflection();
7263 
7264 	reflector_ptr = register_class_Reflector(zend_ce_stringable);
7265 
7266 	reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr);
7267 	reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers;
7268 	reflection_function_abstract_ptr->create_object = reflection_objects_new;
7269 
7270 	reflection_function_ptr = register_class_ReflectionFunction(reflection_function_abstract_ptr);
7271 	reflection_function_ptr->create_object = reflection_objects_new;
7272 	reflection_function_ptr->default_object_handlers = &reflection_object_handlers;
7273 
7274 	reflection_generator_ptr = register_class_ReflectionGenerator();
7275 	reflection_generator_ptr->create_object = reflection_objects_new;
7276 	reflection_generator_ptr->default_object_handlers = &reflection_object_handlers;
7277 
7278 	reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr);
7279 	reflection_parameter_ptr->create_object = reflection_objects_new;
7280 	reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers;
7281 
7282 	reflection_type_ptr = register_class_ReflectionType(zend_ce_stringable);
7283 	reflection_type_ptr->create_object = reflection_objects_new;
7284 	reflection_type_ptr->default_object_handlers = &reflection_object_handlers;
7285 
7286 	reflection_named_type_ptr = register_class_ReflectionNamedType(reflection_type_ptr);
7287 	reflection_named_type_ptr->create_object = reflection_objects_new;
7288 	reflection_named_type_ptr->default_object_handlers = &reflection_object_handlers;
7289 
7290 	reflection_union_type_ptr = register_class_ReflectionUnionType(reflection_type_ptr);
7291 	reflection_union_type_ptr->create_object = reflection_objects_new;
7292 	reflection_union_type_ptr->default_object_handlers = &reflection_object_handlers;
7293 
7294 	reflection_intersection_type_ptr = register_class_ReflectionIntersectionType(reflection_type_ptr);
7295 	reflection_intersection_type_ptr->create_object = reflection_objects_new;
7296 	reflection_intersection_type_ptr->default_object_handlers = &reflection_object_handlers;
7297 
7298 	reflection_method_ptr = register_class_ReflectionMethod(reflection_function_abstract_ptr);
7299 	reflection_method_ptr->create_object = reflection_objects_new;
7300 	reflection_method_ptr->default_object_handlers = &reflection_object_handlers;
7301 
7302 	reflection_class_ptr = register_class_ReflectionClass(reflector_ptr);
7303 	reflection_class_ptr->create_object = reflection_objects_new;
7304 	reflection_class_ptr->default_object_handlers = &reflection_object_handlers;
7305 
7306 	reflection_object_ptr = register_class_ReflectionObject(reflection_class_ptr);
7307 	reflection_object_ptr->create_object = reflection_objects_new;
7308 	reflection_object_ptr->default_object_handlers = &reflection_object_handlers;
7309 
7310 	reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr);
7311 	reflection_property_ptr->create_object = reflection_objects_new;
7312 	reflection_property_ptr->default_object_handlers = &reflection_object_handlers;
7313 
7314 	reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr);
7315 	reflection_class_constant_ptr->create_object = reflection_objects_new;
7316 	reflection_class_constant_ptr->default_object_handlers = &reflection_object_handlers;
7317 
7318 	reflection_extension_ptr = register_class_ReflectionExtension(reflector_ptr);
7319 	reflection_extension_ptr->create_object = reflection_objects_new;
7320 	reflection_extension_ptr->default_object_handlers = &reflection_object_handlers;
7321 
7322 	reflection_zend_extension_ptr = register_class_ReflectionZendExtension(reflector_ptr);
7323 	reflection_zend_extension_ptr->create_object = reflection_objects_new;
7324 	reflection_zend_extension_ptr->default_object_handlers = &reflection_object_handlers;
7325 
7326 	reflection_reference_ptr = register_class_ReflectionReference();
7327 	reflection_reference_ptr->create_object = reflection_objects_new;
7328 	reflection_reference_ptr->default_object_handlers = &reflection_object_handlers;
7329 
7330 	reflection_attribute_ptr = register_class_ReflectionAttribute(reflector_ptr);
7331 	reflection_attribute_ptr->create_object = reflection_objects_new;
7332 	reflection_attribute_ptr->default_object_handlers = &reflection_object_handlers;
7333 
7334 	reflection_enum_ptr = register_class_ReflectionEnum(reflection_class_ptr);
7335 	reflection_enum_ptr->create_object = reflection_objects_new;
7336 	reflection_enum_ptr->default_object_handlers = &reflection_object_handlers;
7337 
7338 	reflection_enum_unit_case_ptr = register_class_ReflectionEnumUnitCase(reflection_class_constant_ptr);
7339 	reflection_enum_unit_case_ptr->create_object = reflection_objects_new;
7340 	reflection_enum_unit_case_ptr->default_object_handlers = &reflection_object_handlers;
7341 
7342 	reflection_enum_backed_case_ptr = register_class_ReflectionEnumBackedCase(reflection_enum_unit_case_ptr);
7343 	reflection_enum_backed_case_ptr->create_object = reflection_objects_new;
7344 	reflection_enum_backed_case_ptr->default_object_handlers = &reflection_object_handlers;
7345 
7346 	reflection_fiber_ptr = register_class_ReflectionFiber();
7347 	reflection_fiber_ptr->create_object = reflection_objects_new;
7348 	reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers;
7349 
7350 	reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr);
7351 	reflection_constant_ptr->create_object = reflection_objects_new;
7352 	reflection_constant_ptr->default_object_handlers = &reflection_object_handlers;
7353 
7354 	REFLECTION_G(key_initialized) = 0;
7355 
7356 	return SUCCESS;
7357 } /* }}} */
7358 
PHP_MINFO_FUNCTION(reflection)7359 PHP_MINFO_FUNCTION(reflection) /* {{{ */
7360 {
7361 	php_info_print_table_start();
7362 	php_info_print_table_row(2, "Reflection", "enabled");
7363 	php_info_print_table_end();
7364 } /* }}} */
7365 
7366 zend_module_entry reflection_module_entry = { /* {{{ */
7367 	STANDARD_MODULE_HEADER,
7368 	"Reflection",
7369 	NULL,
7370 	PHP_MINIT(reflection),
7371 	NULL,
7372 	NULL,
7373 	NULL,
7374 	PHP_MINFO(reflection),
7375 	PHP_REFLECTION_VERSION,
7376 	ZEND_MODULE_GLOBALS(reflection),
7377 	NULL,
7378 	NULL,
7379 	NULL,
7380 	STANDARD_MODULE_PROPERTIES_EX
7381 }; /* }}} */
7382