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