1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) The PHP Group                                          |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Timm Friebe <thekid@thekid.de>                              |
16    |          George Schlossnagle <george@omniti.com>                     |
17    |          Andrei Zmievski <andrei@gravitonic.com>                     |
18    |          Marcus Boerger <helly@php.net>                              |
19    |          Johannes Schlueter <johannes@php.net>                       |
20    +----------------------------------------------------------------------+
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "php.h"
28 #include "php_ini.h"
29 #include "php_reflection.h"
30 #include "ext/standard/info.h"
31 #include "ext/standard/sha1.h"
32 #include "ext/standard/php_random.h"
33 
34 #include "zend.h"
35 #include "zend_API.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 
47 /* Key used to avoid leaking addresses in ReflectionProperty::getId() */
48 #define REFLECTION_KEY_LEN 16
49 ZEND_BEGIN_MODULE_GLOBALS(reflection)
50 	zend_bool key_initialized;
51 	unsigned char key[REFLECTION_KEY_LEN];
52 ZEND_END_MODULE_GLOBALS(reflection)
53 ZEND_DECLARE_MODULE_GLOBALS(reflection)
54 
55 #define REFLECTION_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(reflection, v)
56 
reflection_prop_name(zval *object)57 static zend_always_inline zval *reflection_prop_name(zval *object) {
58 	/* $name is always in the first property slot. */
59 	ZEND_ASSERT(Z_OBJCE_P(object)->default_properties_count >= 1);
60 	return &Z_OBJ_P(object)->properties_table[0];
61 }
62 
reflection_prop_class(zval *object)63 static zend_always_inline zval *reflection_prop_class(zval *object) {
64 	/* $class is always in the second property slot. */
65 	ZEND_ASSERT(Z_OBJCE_P(object)->default_properties_count >= 2);
66 	return &Z_OBJ_P(object)->properties_table[1];
67 }
68 
69 /* Class entry pointers */
70 PHPAPI zend_class_entry *reflector_ptr;
71 PHPAPI zend_class_entry *reflection_exception_ptr;
72 PHPAPI zend_class_entry *reflection_ptr;
73 PHPAPI zend_class_entry *reflection_function_abstract_ptr;
74 PHPAPI zend_class_entry *reflection_function_ptr;
75 PHPAPI zend_class_entry *reflection_generator_ptr;
76 PHPAPI zend_class_entry *reflection_parameter_ptr;
77 PHPAPI zend_class_entry *reflection_type_ptr;
78 PHPAPI zend_class_entry *reflection_named_type_ptr;
79 PHPAPI zend_class_entry *reflection_class_ptr;
80 PHPAPI zend_class_entry *reflection_object_ptr;
81 PHPAPI zend_class_entry *reflection_method_ptr;
82 PHPAPI zend_class_entry *reflection_property_ptr;
83 PHPAPI zend_class_entry *reflection_class_constant_ptr;
84 PHPAPI zend_class_entry *reflection_extension_ptr;
85 PHPAPI zend_class_entry *reflection_zend_extension_ptr;
86 PHPAPI zend_class_entry *reflection_reference_ptr;
87 
88 /* Exception throwing macro */
89 #define _DO_THROW(msg) \
90 	zend_throw_exception(reflection_exception_ptr, msg, 0);
91 
92 #define GET_REFLECTION_OBJECT() do { \
93 	intern = Z_REFLECTION_P(ZEND_THIS); \
94 	if (intern->ptr == NULL) { \
95 		if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { \
96 			return; \
97 		} \
98 		zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); \
99 		return; \
100 	} \
101 } while (0)
102 
103 #define GET_REFLECTION_OBJECT_PTR(target) do { \
104 	GET_REFLECTION_OBJECT(); \
105 	target = intern->ptr; \
106 } while (0)
107 
108 /* Class constants */
109 #define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value) \
110 	zend_declare_class_constant_long(reflection_ ## class_name ## _ptr, const_name, sizeof(const_name)-1, (zend_long)value);
111 
112 /* {{{ Object structure */
113 
114 /* Struct for properties */
115 typedef struct _property_reference {
116 	zend_property_info prop;
117 	zend_string *unmangled_name;
118 	zend_bool dynamic;
119 } property_reference;
120 
121 /* Struct for parameters */
122 typedef struct _parameter_reference {
123 	uint32_t offset;
124 	zend_bool required;
125 	struct _zend_arg_info *arg_info;
126 	zend_function *fptr;
127 } parameter_reference;
128 
129 /* Struct for type hints */
130 typedef struct _type_reference {
131 	zend_type type;
132 } type_reference;
133 
134 typedef enum {
135 	REF_TYPE_OTHER,      /* Must be 0 */
136 	REF_TYPE_FUNCTION,
137 	REF_TYPE_GENERATOR,
138 	REF_TYPE_PARAMETER,
139 	REF_TYPE_TYPE,
140 	REF_TYPE_PROPERTY,
141 	REF_TYPE_CLASS_CONSTANT
142 } reflection_type_t;
143 
144 /* Struct for reflection objects */
145 typedef struct {
146 	zval obj;
147 	void *ptr;
148 	zend_class_entry *ce;
149 	reflection_type_t ref_type;
150 	unsigned int ignore_visibility:1;
151 	zend_object zo;
152 } reflection_object;
153 
reflection_object_from_obj(zend_object *obj)154 static inline reflection_object *reflection_object_from_obj(zend_object *obj) {
155 	return (reflection_object*)((char*)(obj) - XtOffsetOf(reflection_object, zo));
156 }
157 
158 #define Z_REFLECTION_P(zv)  reflection_object_from_obj(Z_OBJ_P((zv)))
159 /* }}} */
160 
161 static zend_object_handlers reflection_object_handlers;
162 
is_closure_invoke(zend_class_entry *ce, zend_string *lcname)163 static inline zend_bool is_closure_invoke(zend_class_entry *ce, zend_string *lcname) {
164 	return ce == zend_ce_closure
165 		&& zend_string_equals_literal(lcname, ZEND_INVOKE_FUNC_NAME);
166 }
167 
_default_load_name(zval *object)168 static zval *_default_load_name(zval *object) /* {{{ */
169 {
170 	return zend_hash_find_ex_ind(Z_OBJPROP_P(object), ZSTR_KNOWN(ZEND_STR_NAME), 1);
171 }
172 /* }}} */
173 
_default_get_name(zval *object, zval *return_value)174 static void _default_get_name(zval *object, zval *return_value) /* {{{ */
175 {
176 	zval *value;
177 
178 	if ((value = _default_load_name(object)) == NULL) {
179 		RETURN_FALSE;
180 	}
181 	ZVAL_COPY(return_value, value);
182 }
183 /* }}} */
184 
_copy_function(zend_function *fptr)185 static zend_function *_copy_function(zend_function *fptr) /* {{{ */
186 {
187 	if (fptr
188 		&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
189 	{
190 		zend_function *copy_fptr;
191 		copy_fptr = emalloc(sizeof(zend_function));
192 		memcpy(copy_fptr, fptr, sizeof(zend_function));
193 		copy_fptr->internal_function.function_name = zend_string_copy(fptr->internal_function.function_name);
194 		return copy_fptr;
195 	} else {
196 		/* no copy needed */
197 		return fptr;
198 	}
199 }
200 /* }}} */
201 
_free_function(zend_function *fptr)202 static void _free_function(zend_function *fptr) /* {{{ */
203 {
204 	if (fptr
205 		&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
206 	{
207 		zend_string_release_ex(fptr->internal_function.function_name, 0);
208 		zend_free_trampoline(fptr);
209 	}
210 }
211 /* }}} */
212 
reflection_free_objects_storage(zend_object *object)213 static void reflection_free_objects_storage(zend_object *object) /* {{{ */
214 {
215 	reflection_object *intern = reflection_object_from_obj(object);
216 	parameter_reference *reference;
217 	property_reference *prop_reference;
218 
219 	if (intern->ptr) {
220 		switch (intern->ref_type) {
221 		case REF_TYPE_PARAMETER:
222 			reference = (parameter_reference*)intern->ptr;
223 			_free_function(reference->fptr);
224 			efree(intern->ptr);
225 			break;
226 		case REF_TYPE_TYPE:
227 		{
228 			type_reference *type_ref = intern->ptr;
229 			if (ZEND_TYPE_IS_NAME(type_ref->type)) {
230 				zend_string_release(ZEND_TYPE_NAME(type_ref->type));
231 			}
232 			efree(type_ref);
233 			break;
234 		}
235 		case REF_TYPE_FUNCTION:
236 			_free_function(intern->ptr);
237 			break;
238 		case REF_TYPE_PROPERTY:
239 			prop_reference = (property_reference*)intern->ptr;
240 			zend_string_release_ex(prop_reference->unmangled_name, 0);
241 
242 			if (ZEND_TYPE_IS_NAME(prop_reference->prop.type)) {
243 				zend_string_release(ZEND_TYPE_NAME(prop_reference->prop.type));
244 			}
245 
246 			efree(intern->ptr);
247 			break;
248 		case REF_TYPE_GENERATOR:
249 		case REF_TYPE_CLASS_CONSTANT:
250 		case REF_TYPE_OTHER:
251 			break;
252 		}
253 	}
254 	intern->ptr = NULL;
255 	zval_ptr_dtor(&intern->obj);
256 	zend_object_std_dtor(object);
257 }
258 /* }}} */
259 
reflection_get_gc(zval *obj, zval **gc_data, int *gc_data_count)260 static HashTable *reflection_get_gc(zval *obj, zval **gc_data, int *gc_data_count) /* {{{ */
261 {
262 	reflection_object *intern = Z_REFLECTION_P(obj);
263 	*gc_data = &intern->obj;
264 	*gc_data_count = 1;
265 	return zend_std_get_properties(obj);
266 }
267 /* }}} */
268 
reflection_objects_new(zend_class_entry *class_type)269 static zend_object *reflection_objects_new(zend_class_entry *class_type) /* {{{ */
270 {
271 	reflection_object *intern = zend_object_alloc(sizeof(reflection_object), class_type);
272 
273 	zend_object_std_init(&intern->zo, class_type);
274 	object_properties_init(&intern->zo, class_type);
275 	intern->zo.handlers = &reflection_object_handlers;
276 	return &intern->zo;
277 }
278 /* }}} */
279 
reflection_instantiate(zend_class_entry *pce, zval *object)280 static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
281 {
282 	object_init_ex(object, pce);
283 	return object;
284 }
285 /* }}} */
286 
287 static void _const_string(smart_str *str, char *name, zval *value, char *indent);
288 static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent);
289 static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent, zend_bool dynamic);
290 static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char* indent);
291 static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent);
292 static void _extension_string(smart_str *str, zend_module_entry *module, char *indent);
293 static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent);
294 
295 /* {{{ _class_string */
_class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent)296 static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent)
297 {
298 	int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
299 	zend_string *sub_indent = strpprintf(0, "%s    ", indent);
300 
301 	/* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
302 	if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) {
303 		smart_str_append_printf(str, "%s%s", indent, ZSTR_VAL(ce->info.user.doc_comment));
304 		smart_str_appendc(str, '\n');
305 	}
306 
307 	if (obj && Z_TYPE_P(obj) == IS_OBJECT) {
308 		smart_str_append_printf(str, "%sObject of class [ ", indent);
309 	} else {
310 		char *kind = "Class";
311 		if (ce->ce_flags & ZEND_ACC_INTERFACE) {
312 			kind = "Interface";
313 		} else if (ce->ce_flags & ZEND_ACC_TRAIT) {
314 			kind = "Trait";
315 		}
316 		smart_str_append_printf(str, "%s%s [ ", indent, kind);
317 	}
318 	smart_str_append_printf(str, (ce->type == ZEND_USER_CLASS) ? "<user" : "<internal");
319 	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module) {
320 		smart_str_append_printf(str, ":%s", ce->info.internal.module->name);
321 	}
322 	smart_str_append_printf(str, "> ");
323 	if (ce->get_iterator != NULL) {
324 		smart_str_append_printf(str, "<iterateable> ");
325 	}
326 	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
327 		smart_str_append_printf(str, "interface ");
328 	} else if (ce->ce_flags & ZEND_ACC_TRAIT) {
329 		smart_str_append_printf(str, "trait ");
330 	} else {
331 		if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
332 			smart_str_append_printf(str, "abstract ");
333 		}
334 		if (ce->ce_flags & ZEND_ACC_FINAL) {
335 			smart_str_append_printf(str, "final ");
336 		}
337 		smart_str_append_printf(str, "class ");
338 	}
339 	smart_str_append_printf(str, "%s", ZSTR_VAL(ce->name));
340 	if (ce->parent) {
341 		smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->parent->name));
342 	}
343 
344 	if (ce->num_interfaces) {
345 		uint32_t i;
346 
347 		ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
348 		if (ce->ce_flags & ZEND_ACC_INTERFACE) {
349 			smart_str_append_printf(str, " extends %s", ZSTR_VAL(ce->interfaces[0]->name));
350 		} else {
351 			smart_str_append_printf(str, " implements %s", ZSTR_VAL(ce->interfaces[0]->name));
352 		}
353 		for (i = 1; i < ce->num_interfaces; ++i) {
354 			smart_str_append_printf(str, ", %s", ZSTR_VAL(ce->interfaces[i]->name));
355 		}
356 	}
357 	smart_str_append_printf(str, " ] {\n");
358 
359 	/* The information where a class is declared is only available for user classes */
360 	if (ce->type == ZEND_USER_CLASS) {
361 		smart_str_append_printf(str, "%s  @@ %s %d-%d\n", indent, ZSTR_VAL(ce->info.user.filename),
362 						ce->info.user.line_start, ce->info.user.line_end);
363 	}
364 
365 	/* Constants */
366 	smart_str_append_printf(str, "\n");
367 	count = zend_hash_num_elements(&ce->constants_table);
368 	smart_str_append_printf(str, "%s  - Constants [%d] {\n", indent, count);
369 	if (count > 0) {
370 		zend_string *key;
371 		zend_class_constant *c;
372 
373 		ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
374 			_class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent));
375 			if (UNEXPECTED(EG(exception))) {
376 				zend_string_release(sub_indent);
377 				return;
378 			}
379 		} ZEND_HASH_FOREACH_END();
380 	}
381 	smart_str_append_printf(str, "%s  }\n", indent);
382 
383 	/* Static properties */
384 	/* counting static properties */
385 	count = zend_hash_num_elements(&ce->properties_info);
386 	if (count > 0) {
387 		zend_property_info *prop;
388 
389 		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
390 			if ((prop->flags & ZEND_ACC_PRIVATE) && prop->ce != ce) {
391 				count_shadow_props++;
392 			} else if (prop->flags & ZEND_ACC_STATIC) {
393 				count_static_props++;
394 			}
395 		} ZEND_HASH_FOREACH_END();
396 	}
397 
398 	/* static properties */
399 	smart_str_append_printf(str, "\n%s  - Static properties [%d] {\n", indent, count_static_props);
400 	if (count_static_props > 0) {
401 		zend_property_info *prop;
402 
403 		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
404 			if ((prop->flags & ZEND_ACC_STATIC) && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) {
405 				_property_string(str, prop, NULL, ZSTR_VAL(sub_indent), 0);
406 			}
407 		} ZEND_HASH_FOREACH_END();
408 	}
409 	smart_str_append_printf(str, "%s  }\n", indent);
410 
411 	/* Static methods */
412 	/* counting static methods */
413 	count = zend_hash_num_elements(&ce->function_table);
414 	if (count > 0) {
415 		zend_function *mptr;
416 
417 		ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) {
418 			if (mptr->common.fn_flags & ZEND_ACC_STATIC
419 				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
420 			{
421 				count_static_funcs++;
422 			}
423 		} ZEND_HASH_FOREACH_END();
424 	}
425 
426 	/* static methods */
427 	smart_str_append_printf(str, "\n%s  - Static methods [%d] {", indent, count_static_funcs);
428 	if (count_static_funcs > 0) {
429 		zend_function *mptr;
430 
431 		ZEND_HASH_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 				smart_str_append_printf(str, "\n");
436 				_function_string(str, mptr, ce, ZSTR_VAL(sub_indent));
437 			}
438 		} ZEND_HASH_FOREACH_END();
439 	} else {
440 		smart_str_append_printf(str, "\n");
441 	}
442 	smart_str_append_printf(str, "%s  }\n", indent);
443 
444 	/* Default/Implicit properties */
445 	count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
446 	smart_str_append_printf(str, "\n%s  - Properties [%d] {\n", indent, count);
447 	if (count > 0) {
448 		zend_property_info *prop;
449 
450 		ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
451 			if (!(prop->flags & ZEND_ACC_STATIC)
452 			 && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) {
453 				_property_string(str, prop, NULL, ZSTR_VAL(sub_indent), 0);
454 			}
455 		} ZEND_HASH_FOREACH_END();
456 	}
457 	smart_str_append_printf(str, "%s  }\n", indent);
458 
459 	if (obj && Z_TYPE_P(obj) == IS_OBJECT) {
460 		HashTable    *properties = Z_OBJ_HT_P(obj)->get_properties(obj);
461 		zend_string  *prop_name;
462 		smart_str prop_str = {0};
463 
464 		count = 0;
465 		if (properties && zend_hash_num_elements(properties)) {
466 			ZEND_HASH_FOREACH_STR_KEY(properties, prop_name) {
467 				if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */
468 					if (!zend_hash_exists(&ce->properties_info, prop_name)) {
469 						count++;
470 						_property_string(&prop_str, NULL, ZSTR_VAL(prop_name), ZSTR_VAL(sub_indent), 0);
471 					}
472 				}
473 			} ZEND_HASH_FOREACH_END();
474 		}
475 
476 		smart_str_append_printf(str, "\n%s  - Dynamic properties [%d] {\n", indent, count);
477 		smart_str_append_smart_str(str, &prop_str);
478 		smart_str_append_printf(str, "%s  }\n", indent);
479 		smart_str_free(&prop_str);
480 	}
481 
482 	/* Non static methods */
483 	count = zend_hash_num_elements(&ce->function_table) - count_static_funcs;
484 	if (count > 0) {
485 		zend_function *mptr;
486 		smart_str method_str = {0};
487 
488 		count = 0;
489 		ZEND_HASH_FOREACH_PTR(&ce->function_table, mptr) {
490 			if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0
491 				&& ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
492 			{
493 				zend_function *closure;
494 				/* see if this is a closure */
495 				if (obj && is_closure_invoke(ce, mptr->common.function_name)
496 					&& (closure = zend_get_closure_invoke_method(Z_OBJ_P(obj))) != NULL)
497 				{
498 					mptr = closure;
499 				} else {
500 					closure = NULL;
501 				}
502 				smart_str_appendc(&method_str, '\n');
503 				_function_string(&method_str, mptr, ce, ZSTR_VAL(sub_indent));
504 				count++;
505 				_free_function(closure);
506 			}
507 		} ZEND_HASH_FOREACH_END();
508 		smart_str_append_printf(str, "\n%s  - Methods [%d] {", indent, count);
509 		smart_str_append_smart_str(str, &method_str);
510 		if (!count) {
511 			smart_str_append_printf(str, "\n");
512 		}
513 		smart_str_free(&method_str);
514 	} else {
515 		smart_str_append_printf(str, "\n%s  - Methods [0] {\n", indent);
516 	}
517 	smart_str_append_printf(str, "%s  }\n", indent);
518 
519 	smart_str_append_printf(str, "%s}\n", indent);
520 	zend_string_release_ex(sub_indent, 0);
521 }
522 /* }}} */
523 
524 /* {{{ _const_string */
_const_string(smart_str *str, char *name, zval *value, char *indent)525 static void _const_string(smart_str *str, char *name, zval *value, char *indent)
526 {
527 	char *type = zend_zval_type_name(value);
528 
529 	if (Z_TYPE_P(value) == IS_ARRAY) {
530 		smart_str_append_printf(str, "%s    Constant [ %s %s ] { Array }\n",
531 						indent, type, name);
532 	} else if (Z_TYPE_P(value) == IS_STRING) {
533 		smart_str_append_printf(str, "%s    Constant [ %s %s ] { %s }\n",
534 						indent, type, name, Z_STRVAL_P(value));
535 	} else {
536 		zend_string *tmp_value_str;
537 		zend_string *value_str = zval_get_tmp_string(value, &tmp_value_str);
538 		smart_str_append_printf(str, "%s    Constant [ %s %s ] { %s }\n",
539 						indent, type, name, ZSTR_VAL(value_str));
540 		zend_tmp_string_release(tmp_value_str);
541 	}
542 }
543 /* }}} */
544 
545 /* {{{ _class_const_string */
_class_const_string(smart_str *str, char *name, zend_class_constant *c, char *indent)546 static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char *indent)
547 {
548 	char *visibility = zend_visibility_string(Z_ACCESS_FLAGS(c->value));
549 	char *type;
550 
551 	if (zval_update_constant_ex(&c->value, c->ce) == FAILURE) {
552 		return;
553 	}
554 
555 	type = zend_zval_type_name(&c->value);
556 
557 	if (Z_TYPE(c->value) == IS_ARRAY) {
558 		smart_str_append_printf(str, "%sConstant [ %s %s %s ] { Array }\n",
559 						indent, visibility, type, name);
560 	} else {
561 		zend_string *tmp_value_str;
562 		zend_string *value_str = zval_get_tmp_string(&c->value, &tmp_value_str);
563 
564 		smart_str_append_printf(str, "%sConstant [ %s %s %s ] { %s }\n",
565 						indent, visibility, type, name, ZSTR_VAL(value_str));
566 
567 		zend_tmp_string_release(tmp_value_str);
568 	}
569 }
570 /* }}} */
571 
572 /* {{{ _get_recv_opcode */
_get_recv_op(zend_op_array *op_array, uint32_t offset)573 static zend_op* _get_recv_op(zend_op_array *op_array, uint32_t offset)
574 {
575 	zend_op *op = op_array->opcodes;
576 	zend_op *end = op + op_array->last;
577 
578 	++offset;
579 	while (op < end) {
580 		if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT
581 		    || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == offset)
582 		{
583 			return op;
584 		}
585 		++op;
586 	}
587 	return NULL;
588 }
589 /* }}} */
590 
591 /* {{{ _parameter_string */
_parameter_string(smart_str *str, zend_function *fptr, struct _zend_arg_info *arg_info, uint32_t offset, zend_bool required, char* indent)592 static void _parameter_string(smart_str *str, zend_function *fptr, struct _zend_arg_info *arg_info, uint32_t offset, zend_bool required, char* indent)
593 {
594 	smart_str_append_printf(str, "Parameter #%d [ ", offset);
595 	if (!required) {
596 		smart_str_append_printf(str, "<optional> ");
597 	} else {
598 		smart_str_append_printf(str, "<required> ");
599 	}
600 	if (ZEND_TYPE_IS_CLASS(arg_info->type)) {
601 		smart_str_append_printf(str, "%s ",
602 			ZSTR_VAL(ZEND_TYPE_NAME(arg_info->type)));
603 		if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
604 			smart_str_append_printf(str, "or NULL ");
605 		}
606 	} else if (ZEND_TYPE_IS_CODE(arg_info->type)) {
607 		smart_str_append_printf(str, "%s ", zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)));
608 		if (ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
609 			smart_str_append_printf(str, "or NULL ");
610 		}
611 	}
612 	if (arg_info->pass_by_reference) {
613 		smart_str_appendc(str, '&');
614 	}
615 	if (arg_info->is_variadic) {
616 		smart_str_appends(str, "...");
617 	}
618 	if (arg_info->name) {
619 		smart_str_append_printf(str, "$%s",
620 			(fptr->type == ZEND_INTERNAL_FUNCTION &&
621 			 !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) ?
622 			((zend_internal_arg_info*)arg_info)->name :
623 			ZSTR_VAL(arg_info->name));
624 	} else {
625 		smart_str_append_printf(str, "$param%d", offset);
626 	}
627 	if (fptr->type == ZEND_USER_FUNCTION && !required) {
628 		zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset);
629 		if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
630 			zval zv;
631 
632 			smart_str_appends(str, " = ");
633 			ZVAL_COPY(&zv, RT_CONSTANT(precv, precv->op2));
634 			if (UNEXPECTED(zval_update_constant_ex(&zv, fptr->common.scope) == FAILURE)) {
635 				zval_ptr_dtor(&zv);
636 				return;
637 			}
638 			if (Z_TYPE(zv) == IS_TRUE) {
639 				smart_str_appends(str, "true");
640 			} else if (Z_TYPE(zv) == IS_FALSE) {
641 				smart_str_appends(str, "false");
642 			} else if (Z_TYPE(zv) == IS_NULL) {
643 				smart_str_appends(str, "NULL");
644 			} else if (Z_TYPE(zv) == IS_STRING) {
645 				smart_str_appendc(str, '\'');
646 				smart_str_appendl(str, Z_STRVAL(zv), MIN(Z_STRLEN(zv), 15));
647 				if (Z_STRLEN(zv) > 15) {
648 					smart_str_appends(str, "...");
649 				}
650 				smart_str_appendc(str, '\'');
651 			} else if (Z_TYPE(zv) == IS_ARRAY) {
652 				smart_str_appends(str, "Array");
653 			} else {
654 				zend_string *tmp_zv_str;
655 				zend_string *zv_str = zval_get_tmp_string(&zv, &tmp_zv_str);
656 				smart_str_append(str, zv_str);
657 				zend_tmp_string_release(tmp_zv_str);
658 			}
659 			zval_ptr_dtor(&zv);
660 		}
661 	}
662 	smart_str_appends(str, " ]");
663 }
664 /* }}} */
665 
666 /* {{{ _function_parameter_string */
_function_parameter_string(smart_str *str, zend_function *fptr, char* indent)667 static void _function_parameter_string(smart_str *str, zend_function *fptr, char* indent)
668 {
669 	struct _zend_arg_info *arg_info = fptr->common.arg_info;
670 	uint32_t i, num_args, num_required = fptr->common.required_num_args;
671 
672 	if (!arg_info) {
673 		return;
674 	}
675 
676 	num_args = fptr->common.num_args;
677 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
678 		num_args++;
679 	}
680 	smart_str_appendc(str, '\n');
681 	smart_str_append_printf(str, "%s- Parameters [%d] {\n", indent, num_args);
682 	for (i = 0; i < num_args; i++) {
683 		smart_str_append_printf(str, "%s  ", indent);
684 		_parameter_string(str, fptr, arg_info, i, i < num_required, indent);
685 		smart_str_appendc(str, '\n');
686 		arg_info++;
687 	}
688 	smart_str_append_printf(str, "%s}\n", indent);
689 }
690 /* }}} */
691 
692 /* {{{ _function_closure_string */
_function_closure_string(smart_str *str, zend_function *fptr, char* indent)693 static void _function_closure_string(smart_str *str, zend_function *fptr, char* indent)
694 {
695 	uint32_t i, count;
696 	zend_string *key;
697 	HashTable *static_variables;
698 
699 	if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) {
700 		return;
701 	}
702 
703 	static_variables = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
704 	count = zend_hash_num_elements(static_variables);
705 
706 	if (!count) {
707 		return;
708 	}
709 
710 	smart_str_append_printf(str, "\n");
711 	smart_str_append_printf(str, "%s- Bound Variables [%d] {\n", indent, zend_hash_num_elements(static_variables));
712 	i = 0;
713 	ZEND_HASH_FOREACH_STR_KEY(static_variables, key) {
714 		smart_str_append_printf(str, "%s    Variable #%d [ $%s ]\n", indent, i++, ZSTR_VAL(key));
715 	} ZEND_HASH_FOREACH_END();
716 	smart_str_append_printf(str, "%s}\n", indent);
717 }
718 /* }}} */
719 
720 /* {{{ _function_string */
_function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent)721 static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent)
722 {
723 	smart_str param_indent = {0};
724 	zend_function *overwrites;
725 	zend_string *lc_name;
726 
727 	/* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
728 	 * What's "wrong" is that any whitespace before the doc comment start is
729 	 * swallowed, leading to an unaligned comment.
730 	 */
731 	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
732 		smart_str_append_printf(str, "%s%s\n", indent, ZSTR_VAL(fptr->op_array.doc_comment));
733 	}
734 
735 	smart_str_appendl(str, indent, strlen(indent));
736 	smart_str_append_printf(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ "));
737 	smart_str_append_printf(str, (fptr->type == ZEND_USER_FUNCTION) ? "<user" : "<internal");
738 	if (fptr->common.fn_flags & ZEND_ACC_DEPRECATED) {
739 		smart_str_appends(str, ", deprecated");
740 	}
741 	if (fptr->type == ZEND_INTERNAL_FUNCTION && ((zend_internal_function*)fptr)->module) {
742 		smart_str_append_printf(str, ":%s", ((zend_internal_function*)fptr)->module->name);
743 	}
744 
745 	if (scope && fptr->common.scope) {
746 		if (fptr->common.scope != scope) {
747 			smart_str_append_printf(str, ", inherits %s", ZSTR_VAL(fptr->common.scope->name));
748 		} else if (fptr->common.scope->parent) {
749 			lc_name = zend_string_tolower(fptr->common.function_name);
750 			if ((overwrites = zend_hash_find_ptr(&fptr->common.scope->parent->function_table, lc_name)) != NULL) {
751 				if (fptr->common.scope != overwrites->common.scope) {
752 					smart_str_append_printf(str, ", overwrites %s", ZSTR_VAL(overwrites->common.scope->name));
753 				}
754 			}
755 			zend_string_release_ex(lc_name, 0);
756 		}
757 	}
758 	if (fptr->common.prototype && fptr->common.prototype->common.scope) {
759 		smart_str_append_printf(str, ", prototype %s", ZSTR_VAL(fptr->common.prototype->common.scope->name));
760 	}
761 	if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
762 		smart_str_appends(str, ", ctor");
763 	}
764 	if (fptr->common.fn_flags & ZEND_ACC_DTOR) {
765 		smart_str_appends(str, ", dtor");
766 	}
767 	smart_str_appends(str, "> ");
768 
769 	if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
770 		smart_str_appends(str, "abstract ");
771 	}
772 	if (fptr->common.fn_flags & ZEND_ACC_FINAL) {
773 		smart_str_appends(str, "final ");
774 	}
775 	if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
776 		smart_str_appends(str, "static ");
777 	}
778 
779 	if (fptr->common.scope) {
780 		/* These are mutually exclusive */
781 		switch (fptr->common.fn_flags & ZEND_ACC_PPP_MASK) {
782 			case ZEND_ACC_PUBLIC:
783 				smart_str_appends(str, "public ");
784 				break;
785 			case ZEND_ACC_PRIVATE:
786 				smart_str_appends(str, "private ");
787 				break;
788 			case ZEND_ACC_PROTECTED:
789 				smart_str_appends(str, "protected ");
790 				break;
791 			default:
792 				smart_str_appends(str, "<visibility error> ");
793 				break;
794 		}
795 		smart_str_appends(str, "method ");
796 	} else {
797 		smart_str_appends(str, "function ");
798 	}
799 
800 	if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
801 		smart_str_appendc(str, '&');
802 	}
803 	smart_str_append_printf(str, "%s ] {\n", ZSTR_VAL(fptr->common.function_name));
804 	/* The information where a function is declared is only available for user classes */
805 	if (fptr->type == ZEND_USER_FUNCTION) {
806 		smart_str_append_printf(str, "%s  @@ %s %d - %d\n", indent,
807 						ZSTR_VAL(fptr->op_array.filename),
808 						fptr->op_array.line_start,
809 						fptr->op_array.line_end);
810 	}
811 	smart_str_append_printf(&param_indent, "%s  ", indent);
812 	smart_str_0(&param_indent);
813 	if (fptr->common.fn_flags & ZEND_ACC_CLOSURE) {
814 		_function_closure_string(str, fptr, ZSTR_VAL(param_indent.s));
815 	}
816 	_function_parameter_string(str, fptr, ZSTR_VAL(param_indent.s));
817 	smart_str_free(&param_indent);
818 	if (fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
819 		smart_str_append_printf(str, "  %s- Return [ ", indent);
820 		if (ZEND_TYPE_IS_CLASS(fptr->common.arg_info[-1].type)) {
821 			smart_str_append_printf(str, "%s ",
822 				ZSTR_VAL(ZEND_TYPE_NAME(fptr->common.arg_info[-1].type)));
823 			if (ZEND_TYPE_ALLOW_NULL(fptr->common.arg_info[-1].type)) {
824 				smart_str_appends(str, "or NULL ");
825 			}
826 		} else if (ZEND_TYPE_IS_CODE(fptr->common.arg_info[-1].type)) {
827 			smart_str_append_printf(str, "%s ", zend_get_type_by_const(ZEND_TYPE_CODE(fptr->common.arg_info[-1].type)));
828 			if (ZEND_TYPE_ALLOW_NULL(fptr->common.arg_info[-1].type)) {
829 				smart_str_appends(str, "or NULL ");
830 			}
831 		}
832 		smart_str_appends(str, "]\n");
833 	}
834 	smart_str_append_printf(str, "%s}\n", indent);
835 }
836 /* }}} */
837 
838 /* {{{ _property_string */
_property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent, zend_bool dynamic)839 static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent, zend_bool dynamic)
840 {
841 	smart_str_append_printf(str, "%sProperty [ ", indent);
842 	if (!prop) {
843 		smart_str_append_printf(str, "<dynamic> public $%s", prop_name);
844 	} else {
845 		if (!(prop->flags & ZEND_ACC_STATIC)) {
846 			if (dynamic) {
847 				smart_str_appends(str, "<implicit> ");
848 			} else {
849 				smart_str_appends(str, "<default> ");
850 			}
851 		}
852 
853 		/* These are mutually exclusive */
854 		switch (prop->flags & ZEND_ACC_PPP_MASK) {
855 			case ZEND_ACC_PUBLIC:
856 				smart_str_appends(str, "public ");
857 				break;
858 			case ZEND_ACC_PRIVATE:
859 				smart_str_appends(str, "private ");
860 				break;
861 			case ZEND_ACC_PROTECTED:
862 				smart_str_appends(str, "protected ");
863 				break;
864 		}
865 		if (prop->flags & ZEND_ACC_STATIC) {
866 			smart_str_appends(str, "static ");
867 		}
868 		if (!prop_name) {
869 			const char *class_name;
870 			zend_unmangle_property_name(prop->name, &class_name, &prop_name);
871 		}
872 		smart_str_append_printf(str, "$%s", prop_name);
873 	}
874 
875 	smart_str_appends(str, " ]\n");
876 }
877 /* }}} */
878 
_extension_ini_string(zend_ini_entry *ini_entry, smart_str *str, char *indent, int number)879 static void _extension_ini_string(zend_ini_entry *ini_entry, smart_str *str, char *indent, int number) /* {{{ */
880 {
881 	char *comma = "";
882 
883 	if (number == ini_entry->module_number) {
884 		smart_str_append_printf(str, "    %sEntry [ %s <", indent, ZSTR_VAL(ini_entry->name));
885 		if (ini_entry->modifiable == ZEND_INI_ALL) {
886 			smart_str_appends(str, "ALL");
887 		} else {
888 			if (ini_entry->modifiable & ZEND_INI_USER) {
889 				smart_str_appends(str, "USER");
890 				comma = ",";
891 			}
892 			if (ini_entry->modifiable & ZEND_INI_PERDIR) {
893 				smart_str_append_printf(str, "%sPERDIR", comma);
894 				comma = ",";
895 			}
896 			if (ini_entry->modifiable & ZEND_INI_SYSTEM) {
897 				smart_str_append_printf(str, "%sSYSTEM", comma);
898 			}
899 		}
900 
901 		smart_str_appends(str, "> ]\n");
902 		smart_str_append_printf(str, "    %s  Current = '%s'\n", indent, ini_entry->value ? ZSTR_VAL(ini_entry->value) : "");
903 		if (ini_entry->modified) {
904 			smart_str_append_printf(str, "    %s  Default = '%s'\n", indent, ini_entry->orig_value ? ZSTR_VAL(ini_entry->orig_value) : "");
905 		}
906 		smart_str_append_printf(str, "    %s}\n", indent);
907 	}
908 }
909 /* }}} */
910 
_extension_class_string(zend_class_entry *ce, zend_string *key, smart_str *str, char *indent, zend_module_entry *module, int *num_classes)911 static void _extension_class_string(zend_class_entry *ce, zend_string *key, smart_str *str, char *indent, zend_module_entry *module, int *num_classes) /* {{{ */
912 {
913 	if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
914 		/* dump class if it is not an alias */
915 		if (zend_string_equals_ci(ce->name, key)) {
916 			smart_str_append_printf(str, "\n");
917 			_class_string(str, ce, NULL, indent);
918 			(*num_classes)++;
919 		}
920 	}
921 }
922 /* }}} */
923 
_extension_string(smart_str *str, zend_module_entry *module, char *indent)924 static void _extension_string(smart_str *str, zend_module_entry *module, char *indent) /* {{{ */
925 {
926 	smart_str_append_printf(str, "%sExtension [ ", indent);
927 	if (module->type == MODULE_PERSISTENT) {
928 		smart_str_appends(str, "<persistent>");
929 	}
930 	if (module->type == MODULE_TEMPORARY) {
931 		smart_str_appends(str, "<temporary>" );
932 	}
933 	smart_str_append_printf(str, " extension #%d %s version %s ] {\n",
934 					module->module_number, module->name,
935 					(module->version == NO_VERSION_YET) ? "<no_version>" : module->version);
936 
937 	if (module->deps) {
938 		const zend_module_dep* dep = module->deps;
939 
940 		smart_str_appends(str, "\n  - Dependencies {\n");
941 
942 		while(dep->name) {
943 			smart_str_append_printf(str, "%s    Dependency [ %s (", indent, dep->name);
944 
945 			switch(dep->type) {
946 			case MODULE_DEP_REQUIRED:
947 				smart_str_appends(str, "Required");
948 				break;
949 			case MODULE_DEP_CONFLICTS:
950 				smart_str_appends(str, "Conflicts");
951 				break;
952 			case MODULE_DEP_OPTIONAL:
953 				smart_str_appends(str, "Optional");
954 				break;
955 			default:
956 				smart_str_appends(str, "Error"); /* shouldn't happen */
957 				break;
958 			}
959 
960 			if (dep->rel) {
961 				smart_str_append_printf(str, " %s", dep->rel);
962 			}
963 			if (dep->version) {
964 				smart_str_append_printf(str, " %s", dep->version);
965 			}
966 			smart_str_appends(str, ") ]\n");
967 			dep++;
968 		}
969 		smart_str_append_printf(str, "%s  }\n", indent);
970 	}
971 
972 	{
973 		smart_str str_ini = {0};
974 		zend_ini_entry *ini_entry;
975 		ZEND_HASH_FOREACH_PTR(EG(ini_directives), ini_entry) {
976 			_extension_ini_string(ini_entry, &str_ini, indent, module->module_number);
977 		} ZEND_HASH_FOREACH_END();
978 		if (smart_str_get_len(&str_ini) > 0) {
979 			smart_str_append_printf(str, "\n  - INI {\n");
980 			smart_str_append_smart_str(str, &str_ini);
981 			smart_str_append_printf(str, "%s  }\n", indent);
982 		}
983 		smart_str_free(&str_ini);
984 	}
985 
986 	{
987 		smart_str str_constants = {0};
988 		zend_constant *constant;
989 		int num_constants = 0;
990 
991 		ZEND_HASH_FOREACH_PTR(EG(zend_constants), constant) {
992 			if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) {
993 				_const_string(&str_constants, ZSTR_VAL(constant->name), &constant->value, indent);
994 				num_constants++;
995 			}
996 		} ZEND_HASH_FOREACH_END();
997 
998 		if (num_constants) {
999 			smart_str_append_printf(str, "\n  - Constants [%d] {\n", num_constants);
1000 			smart_str_append_smart_str(str, &str_constants);
1001 			smart_str_append_printf(str, "%s  }\n", indent);
1002 		}
1003 		smart_str_free(&str_constants);
1004 	}
1005 
1006 	{
1007 		zend_function *fptr;
1008 		int first = 1;
1009 
1010 		ZEND_HASH_FOREACH_PTR(CG(function_table), fptr) {
1011 			if (fptr->common.type==ZEND_INTERNAL_FUNCTION
1012 				&& fptr->internal_function.module == module) {
1013 				if (first) {
1014 					smart_str_append_printf(str, "\n  - Functions {\n");
1015 					first = 0;
1016 				}
1017 				_function_string(str, fptr, NULL, "    ");
1018 			}
1019 		} ZEND_HASH_FOREACH_END();
1020 		if (!first) {
1021 			smart_str_append_printf(str, "%s  }\n", indent);
1022 		}
1023 	}
1024 
1025 	{
1026 		zend_string *sub_indent = strpprintf(0, "%s    ", indent);
1027 		smart_str str_classes = {0};
1028 		zend_string *key;
1029 		zend_class_entry *ce;
1030 		int num_classes = 0;
1031 
1032 		ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), key, ce) {
1033 			_extension_class_string(ce, key, &str_classes, ZSTR_VAL(sub_indent), module, &num_classes);
1034 		} ZEND_HASH_FOREACH_END();
1035 		if (num_classes) {
1036 			smart_str_append_printf(str, "\n  - Classes [%d] {", num_classes);
1037 			smart_str_append_smart_str(str, &str_classes);
1038 			smart_str_append_printf(str, "%s  }\n", indent);
1039 		}
1040 		smart_str_free(&str_classes);
1041 		zend_string_release_ex(sub_indent, 0);
1042 	}
1043 
1044 	smart_str_append_printf(str, "%s}\n", indent);
1045 }
1046 /* }}} */
1047 
_zend_extension_string(smart_str *str, zend_extension *extension, char *indent)1048 static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent) /* {{{ */
1049 {
1050 	smart_str_append_printf(str, "%sZend Extension [ %s ", indent, extension->name);
1051 
1052 	if (extension->version) {
1053 		smart_str_append_printf(str, "%s ", extension->version);
1054 	}
1055 	if (extension->copyright) {
1056 		smart_str_append_printf(str, "%s ", extension->copyright);
1057 	}
1058 	if (extension->author) {
1059 		smart_str_append_printf(str, "by %s ", extension->author);
1060 	}
1061 	if (extension->URL) {
1062 		smart_str_append_printf(str, "<%s> ", extension->URL);
1063 	}
1064 
1065 	smart_str_appends(str, "]\n");
1066 }
1067 /* }}} */
1068 
1069 /* {{{ _function_check_flag */
_function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)1070 static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
1071 {
1072 	reflection_object *intern;
1073 	zend_function *mptr;
1074 
1075 	if (zend_parse_parameters_none() == FAILURE) {
1076 		return;
1077 	}
1078 	GET_REFLECTION_OBJECT_PTR(mptr);
1079 	RETURN_BOOL(mptr->common.fn_flags & mask);
1080 }
1081 /* }}} */
1082 
1083 /* {{{ zend_reflection_class_factory */
zend_reflection_class_factory(zend_class_entry *ce, zval *object)1084 PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object)
1085 {
1086 	reflection_object *intern;
1087 
1088 	reflection_instantiate(reflection_class_ptr, object);
1089 	intern = Z_REFLECTION_P(object);
1090 	intern->ptr = ce;
1091 	intern->ref_type = REF_TYPE_OTHER;
1092 	intern->ce = ce;
1093 	ZVAL_STR_COPY(reflection_prop_name(object), ce->name);
1094 }
1095 /* }}} */
1096 
1097 /* {{{ reflection_extension_factory */
reflection_extension_factory(zval *object, const char *name_str)1098 static void reflection_extension_factory(zval *object, const char *name_str)
1099 {
1100 	reflection_object *intern;
1101 	size_t name_len = strlen(name_str);
1102 	zend_string *lcname;
1103 	struct _zend_module_entry *module;
1104 
1105 	lcname = zend_string_alloc(name_len, 0);
1106 	zend_str_tolower_copy(ZSTR_VAL(lcname), name_str, name_len);
1107 	module = zend_hash_find_ptr(&module_registry, lcname);
1108 	zend_string_efree(lcname);
1109 	if (!module) {
1110 		return;
1111 	}
1112 
1113 	reflection_instantiate(reflection_extension_ptr, object);
1114 	intern = Z_REFLECTION_P(object);
1115 	intern->ptr = module;
1116 	intern->ref_type = REF_TYPE_OTHER;
1117 	intern->ce = NULL;
1118 	ZVAL_STRINGL(reflection_prop_name(object), module->name, name_len);
1119 }
1120 /* }}} */
1121 
1122 /* {{{ reflection_parameter_factory */
reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, uint32_t offset, zend_bool required, zval *object)1123 static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, uint32_t offset, zend_bool required, zval *object)
1124 {
1125 	reflection_object *intern;
1126 	parameter_reference *reference;
1127 	zval *prop_name;
1128 
1129 	reflection_instantiate(reflection_parameter_ptr, object);
1130 	intern = Z_REFLECTION_P(object);
1131 	reference = (parameter_reference*) emalloc(sizeof(parameter_reference));
1132 	reference->arg_info = arg_info;
1133 	reference->offset = offset;
1134 	reference->required = required;
1135 	reference->fptr = fptr;
1136 	intern->ptr = reference;
1137 	intern->ref_type = REF_TYPE_PARAMETER;
1138 	intern->ce = fptr->common.scope;
1139 	if (closure_object) {
1140 		Z_ADDREF_P(closure_object);
1141 		ZVAL_OBJ(&intern->obj, Z_OBJ_P(closure_object));
1142 	}
1143 
1144 	prop_name = reflection_prop_name(object);
1145 	if (arg_info->name) {
1146 		if (fptr->type == ZEND_INTERNAL_FUNCTION &&
1147 		    !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
1148 			ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)->name);
1149 		} else {
1150 			ZVAL_STR_COPY(prop_name, arg_info->name);
1151 		}
1152 	} else {
1153 		ZVAL_NULL(prop_name);
1154 	}
1155 }
1156 /* }}} */
1157 
1158 /* {{{ reflection_type_factory */
reflection_type_factory(zend_type type, zval *object)1159 static void reflection_type_factory(zend_type type, zval *object)
1160 {
1161 	reflection_object *intern;
1162 	type_reference *reference;
1163 
1164 	reflection_instantiate(reflection_named_type_ptr, object);
1165 	intern = Z_REFLECTION_P(object);
1166 	reference = (type_reference*) emalloc(sizeof(type_reference));
1167 	reference->type = type;
1168 	intern->ptr = reference;
1169 	intern->ref_type = REF_TYPE_TYPE;
1170 
1171 	/* Property types may be resolved during the lifetime of the ReflectionType,
1172 	 * so we need to make sure that the strings we reference are not released. */
1173 	if (ZEND_TYPE_IS_NAME(type)) {
1174 		zend_string_addref(ZEND_TYPE_NAME(type));
1175 	}
1176 }
1177 /* }}} */
1178 
1179 /* {{{ reflection_function_factory */
reflection_function_factory(zend_function *function, zval *closure_object, zval *object)1180 static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object)
1181 {
1182 	reflection_object *intern;
1183 	reflection_instantiate(reflection_function_ptr, object);
1184 	intern = Z_REFLECTION_P(object);
1185 	intern->ptr = function;
1186 	intern->ref_type = REF_TYPE_FUNCTION;
1187 	intern->ce = NULL;
1188 	if (closure_object) {
1189 		Z_ADDREF_P(closure_object);
1190 		ZVAL_OBJ(&intern->obj, Z_OBJ_P(closure_object));
1191 	}
1192 	ZVAL_STR_COPY(reflection_prop_name(object), function->common.function_name);
1193 }
1194 /* }}} */
1195 
1196 /* {{{ reflection_method_factory */
reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object)1197 static void reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object)
1198 {
1199 	reflection_object *intern;
1200 
1201 	reflection_instantiate(reflection_method_ptr, object);
1202 	intern = Z_REFLECTION_P(object);
1203 	intern->ptr = method;
1204 	intern->ref_type = REF_TYPE_FUNCTION;
1205 	intern->ce = ce;
1206 	if (closure_object) {
1207 		Z_ADDREF_P(closure_object);
1208 		ZVAL_OBJ(&intern->obj, Z_OBJ_P(closure_object));
1209 	}
1210 
1211 	ZVAL_STR_COPY(reflection_prop_name(object),
1212 		(method->common.scope && method->common.scope->trait_aliases)
1213 			? zend_resolve_method_name(ce, method) : method->common.function_name);
1214 	ZVAL_STR_COPY(reflection_prop_class(object), method->common.scope->name);
1215 }
1216 /* }}} */
1217 
1218 /* {{{ reflection_property_factory */
reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object, zend_bool dynamic)1219 static void reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object, zend_bool dynamic)
1220 {
1221 	reflection_object *intern;
1222 	property_reference *reference;
1223 
1224 	if (!(prop->flags & ZEND_ACC_PRIVATE)) {
1225 		/* we have to search the class hierarchy for this (implicit) public or protected property */
1226 		zend_class_entry *tmp_ce = ce, *store_ce = ce;
1227 		zend_property_info *tmp_info = NULL;
1228 
1229 		while (tmp_ce && (tmp_info = zend_hash_find_ptr(&tmp_ce->properties_info, name)) == NULL) {
1230 			ce = tmp_ce;
1231 			tmp_ce = tmp_ce->parent;
1232 		}
1233 
1234 		if (tmp_info && (!(tmp_info->flags & ZEND_ACC_PRIVATE) || tmp_info->ce == tmp_ce)) { /* found something and it's not a parent's private */
1235 			prop = tmp_info;
1236 		} else { /* not found, use initial value */
1237 			ce = store_ce;
1238 		}
1239 	}
1240 
1241 	reflection_instantiate(reflection_property_ptr, object);
1242 	intern = Z_REFLECTION_P(object);
1243 	reference = (property_reference*) emalloc(sizeof(property_reference));
1244 	reference->prop = *prop;
1245 
1246 	if (ZEND_TYPE_IS_NAME(reference->prop.type)) {
1247 		zend_string_addref(ZEND_TYPE_NAME(reference->prop.type));
1248 	}
1249 
1250 	reference->unmangled_name = zend_string_copy(name);
1251 	reference->dynamic = dynamic;
1252 	intern->ptr = reference;
1253 	intern->ref_type = REF_TYPE_PROPERTY;
1254 	intern->ce = ce;
1255 	intern->ignore_visibility = 0;
1256 	ZVAL_STR_COPY(reflection_prop_name(object), name);
1257 	ZVAL_STR_COPY(reflection_prop_class(object), prop->ce->name);
1258 }
1259 /* }}} */
1260 
reflection_property_factory_str(zend_class_entry *ce, const char *name_str, size_t name_len, zend_property_info *prop, zval *object)1261 static void reflection_property_factory_str(zend_class_entry *ce, const char *name_str, size_t name_len, zend_property_info *prop, zval *object)
1262 {
1263 	zend_string *name = zend_string_init(name_str, name_len, 0);
1264 	reflection_property_factory(ce, name, prop, object, 0);
1265 	zend_string_release(name);
1266 }
1267 
1268 /* {{{ reflection_class_constant_factory */
reflection_class_constant_factory(zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object)1269 static void reflection_class_constant_factory(zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object)
1270 {
1271 	reflection_object *intern;
1272 
1273 	reflection_instantiate(reflection_class_constant_ptr, object);
1274 	intern = Z_REFLECTION_P(object);
1275 	intern->ptr = constant;
1276 	intern->ref_type = REF_TYPE_CLASS_CONSTANT;
1277 	intern->ce = constant->ce;
1278 	intern->ignore_visibility = 0;
1279 
1280 	ZVAL_STR_COPY(reflection_prop_name(object), name_str);
1281 	ZVAL_STR_COPY(reflection_prop_class(object), ce->name);
1282 }
1283 /* }}} */
1284 
reflection_export_impl(zval *return_value, zval *object, zend_bool return_output)1285 static void reflection_export_impl(zval *return_value, zval *object, zend_bool return_output) {
1286 	zval fname, retval;
1287 	int result;
1288 
1289 	/* Invoke the __toString() method */
1290 	ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1);
1291 	result = call_user_function(NULL, object, &fname, &retval, 0, NULL);
1292 	zval_ptr_dtor_str(&fname);
1293 
1294 	if (result == FAILURE) {
1295 		_DO_THROW("Invocation of method __toString() failed");
1296 		return;
1297 	}
1298 
1299 	if (Z_TYPE(retval) == IS_UNDEF) {
1300 		php_error_docref(NULL, E_WARNING, "%s::__toString() did not return anything", ZSTR_VAL(Z_OBJCE_P(object)->name));
1301 		RETURN_FALSE;
1302 	}
1303 
1304 	if (return_output) {
1305 		ZVAL_COPY_VALUE(return_value, &retval);
1306 	} else {
1307 		/* No need for _r variant, return of __toString should always be a string */
1308 		zend_print_zval(&retval, 0);
1309 		zend_printf("\n");
1310 		zval_ptr_dtor(&retval);
1311 	}
1312 }
1313 
1314 /* {{{ _reflection_export */
_reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc)1315 static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc)
1316 {
1317 	zval reflector;
1318 	zval *argument_ptr, *argument2_ptr;
1319 	zval retval, params[2];
1320 	int result;
1321 	int return_output = 0;
1322 	zend_fcall_info fci;
1323 	zend_fcall_info_cache fcc;
1324 
1325 	if (ctor_argc == 1) {
1326 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|b", &argument_ptr, &return_output) == FAILURE) {
1327 			return;
1328 		}
1329 		ZVAL_COPY_VALUE(&params[0], argument_ptr);
1330 		ZVAL_NULL(&params[1]);
1331 	} else {
1332 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|b", &argument_ptr, &argument2_ptr, &return_output) == FAILURE) {
1333 			return;
1334 		}
1335 		ZVAL_COPY_VALUE(&params[0], argument_ptr);
1336 		ZVAL_COPY_VALUE(&params[1], argument2_ptr);
1337 	}
1338 
1339 	/* Create object */
1340 	if (object_init_ex(&reflector, ce_ptr) == FAILURE) {
1341 		_DO_THROW("Could not create reflector");
1342 		return;
1343 	}
1344 
1345 	/* Call __construct() */
1346 
1347 	fci.size = sizeof(fci);
1348 	ZVAL_UNDEF(&fci.function_name);
1349 	fci.object = Z_OBJ(reflector);
1350 	fci.retval = &retval;
1351 	fci.param_count = ctor_argc;
1352 	fci.params = params;
1353 	fci.no_separation = 1;
1354 
1355 	fcc.function_handler = ce_ptr->constructor;
1356 	fcc.called_scope = Z_OBJCE(reflector);
1357 	fcc.object = Z_OBJ(reflector);
1358 
1359 	result = zend_call_function(&fci, &fcc);
1360 
1361 	zval_ptr_dtor(&retval);
1362 
1363 	if (EG(exception)) {
1364 		zval_ptr_dtor(&reflector);
1365 		return;
1366 	}
1367 	if (result == FAILURE) {
1368 		zval_ptr_dtor(&reflector);
1369 		_DO_THROW("Could not create reflector");
1370 		return;
1371 	}
1372 
1373 	reflection_export_impl(return_value, &reflector, return_output);
1374 
1375 	/* Destruct reflector which is no longer needed */
1376 	zval_ptr_dtor(&reflector);
1377 }
1378 /* }}} */
1379 
1380 /* {{{ _reflection_param_get_default_param */
_reflection_param_get_default_paramnull1381 static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTION_PARAMETERS)
1382 {
1383 	reflection_object *intern;
1384 	parameter_reference *param;
1385 
1386 	intern = Z_REFLECTION_P(ZEND_THIS);
1387 	if (intern->ptr == NULL) {
1388 		if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) {
1389 			return NULL;
1390 		}
1391 		zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object");
1392 		return NULL;
1393 	}
1394 
1395 	param = intern->ptr;
1396 	if (param->fptr->type != ZEND_USER_FUNCTION) {
1397 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Cannot determine default value for internal functions");
1398 		return NULL;
1399 	}
1400 
1401 	return param;
1402 }
1403 /* }}} */
1404 
1405 /* {{{ _reflection_param_get_default_precv */
_reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAMETERS, parameter_reference *param)1406 static zend_op *_reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAMETERS, parameter_reference *param)
1407 {
1408 	zend_op *precv;
1409 
1410 	if (param == NULL) {
1411 		return NULL;
1412 	}
1413 
1414 	precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
1415 	if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
1416 		zend_throw_exception_ex(reflection_exception_ptr, 0, "Internal error: Failed to retrieve the default value");
1417 		return NULL;
1418 	}
1419 
1420 	return precv;
1421 }
1422 /* }}} */
1423 
1424 /* {{{ Preventing __clone from being called */
ZEND_METHODnull1425 ZEND_METHOD(reflection, __clone)
1426 {
1427 	/* Should never be executable */
1428 	_DO_THROW("Cannot clone object using __clone()");
1429 }
1430 /* }}} */
1431 
1432 /* {{{ proto public static mixed Reflection::export(Reflector r [, bool return])
1433    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHODnull1434 ZEND_METHOD(reflection, export)
1435 {
1436 	zval *object;
1437 	zend_bool return_output = 0;
1438 
1439 	ZEND_PARSE_PARAMETERS_START(1, 2)
1440 		Z_PARAM_OBJECT_OF_CLASS(object, reflector_ptr)
1441 		Z_PARAM_OPTIONAL
1442 		Z_PARAM_BOOL(return_output)
1443 	ZEND_PARSE_PARAMETERS_END();
1444 
1445 	reflection_export_impl(return_value, object, return_output);
1446 }
1447 /* }}} */
1448 
1449 /* {{{ proto public static array Reflection::getModifierNames(int modifiers)
1450    Returns an array of modifier names */
ZEND_METHODnull1451 ZEND_METHOD(reflection, getModifierNames)
1452 {
1453 	zend_long modifiers;
1454 
1455 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &modifiers) == FAILURE) {
1456 		return;
1457 	}
1458 
1459 	array_init(return_value);
1460 
1461 	if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1462 		add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1);
1463 	}
1464 	if (modifiers & ZEND_ACC_FINAL) {
1465 		add_next_index_stringl(return_value, "final", sizeof("final")-1);
1466 	}
1467 
1468 	/* These are mutually exclusive */
1469 	switch (modifiers & ZEND_ACC_PPP_MASK) {
1470 		case ZEND_ACC_PUBLIC:
1471 			add_next_index_stringl(return_value, "public", sizeof("public")-1);
1472 			break;
1473 		case ZEND_ACC_PRIVATE:
1474 			add_next_index_stringl(return_value, "private", sizeof("private")-1);
1475 			break;
1476 		case ZEND_ACC_PROTECTED:
1477 			add_next_index_stringl(return_value, "protected", sizeof("protected")-1);
1478 			break;
1479 	}
1480 
1481 	if (modifiers & ZEND_ACC_STATIC) {
1482 		add_next_index_stringl(return_value, "static", sizeof("static")-1);
1483 	}
1484 }
1485 /* }}} */
1486 
1487 /* {{{ proto public static mixed ReflectionFunction::export(string name [, bool return])
1488    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHODnull1489 ZEND_METHOD(reflection_function, export)
1490 {
1491 	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_function_ptr, 1);
1492 }
1493 /* }}} */
1494 
1495 /* {{{ proto public void ReflectionFunction::__construct(string name)
1496    Constructor. Throws an Exception in case the given function does not exist */
ZEND_METHODnull1497 ZEND_METHOD(reflection_function, __construct)
1498 {
1499 	zval *object;
1500 	zval *closure = NULL;
1501 	reflection_object *intern;
1502 	zend_function *fptr;
1503 	zend_string *fname, *lcname;
1504 
1505 	object = ZEND_THIS;
1506 	intern = Z_REFLECTION_P(object);
1507 
1508 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == SUCCESS) {
1509 		fptr = (zend_function*)zend_get_closure_method_def(closure);
1510 		Z_ADDREF_P(closure);
1511 	} else {
1512 		ALLOCA_FLAG(use_heap)
1513 
1514 		if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "S", &fname) == FAILURE) {
1515 			return;
1516 		}
1517 
1518 		if (UNEXPECTED(ZSTR_VAL(fname)[0] == '\\')) {
1519 			/* Ignore leading "\" */
1520 			ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(fname) - 1, use_heap);
1521 			zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(fname) + 1, ZSTR_LEN(fname) - 1);
1522 			fptr = zend_fetch_function(lcname);
1523 			ZSTR_ALLOCA_FREE(lcname, use_heap);
1524 		} else {
1525 			lcname = zend_string_tolower(fname);
1526 			fptr = zend_fetch_function(lcname);
1527 			zend_string_release(lcname);
1528 		}
1529 
1530 		if (fptr == NULL) {
1531 			zend_throw_exception_ex(reflection_exception_ptr, 0,
1532 				"Function %s() does not exist", ZSTR_VAL(fname));
1533 			return;
1534 		}
1535 	}
1536 
1537 	if (intern->ptr) {
1538 		zval_ptr_dtor(&intern->obj);
1539 		zval_ptr_dtor(reflection_prop_name(object));
1540 	}
1541 
1542 	ZVAL_STR_COPY(reflection_prop_name(object), fptr->common.function_name);
1543 	intern->ptr = fptr;
1544 	intern->ref_type = REF_TYPE_FUNCTION;
1545 	if (closure) {
1546 		ZVAL_OBJ(&intern->obj, Z_OBJ_P(closure));
1547 	} else {
1548 		ZVAL_UNDEF(&intern->obj);
1549 	}
1550 	intern->ce = NULL;
1551 }
1552 /* }}} */
1553 
1554 /* {{{ proto public string ReflectionFunction::__toString()
1555    Returns a string representation */
ZEND_METHODnull1556 ZEND_METHOD(reflection_function, __toString)
1557 {
1558 	reflection_object *intern;
1559 	zend_function *fptr;
1560 	smart_str str = {0};
1561 
1562 	if (zend_parse_parameters_none() == FAILURE) {
1563 		return;
1564 	}
1565 	GET_REFLECTION_OBJECT_PTR(fptr);
1566 	_function_string(&str, fptr, intern->ce, "");
1567 	RETURN_STR(smart_str_extract(&str));
1568 }
1569 /* }}} */
1570 
1571 /* {{{ proto public string ReflectionFunction::getName()
1572    Returns this function's name */
ZEND_METHODnull1573 ZEND_METHOD(reflection_function, getName)
1574 {
1575 	if (zend_parse_parameters_none() == FAILURE) {
1576 		return;
1577 	}
1578 	_default_get_name(ZEND_THIS, return_value);
1579 }
1580 /* }}} */
1581 
1582 /* {{{ proto public bool ReflectionFunction::isClosure()
1583    Returns whether this is a closure */
ZEND_METHODnull1584 ZEND_METHOD(reflection_function, isClosure)
1585 {
1586 	reflection_object *intern;
1587 	zend_function *fptr;
1588 
1589 	if (zend_parse_parameters_none() == FAILURE) {
1590 		return;
1591 	}
1592 	GET_REFLECTION_OBJECT_PTR(fptr);
1593 	RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_CLOSURE);
1594 }
1595 /* }}} */
1596 
1597 /* {{{ proto public bool ReflectionFunction::getClosureThis()
1598    Returns this pointer bound to closure */
ZEND_METHODnull1599 ZEND_METHOD(reflection_function, getClosureThis)
1600 {
1601 	reflection_object *intern;
1602 	zval* closure_this;
1603 
1604 	if (zend_parse_parameters_none() == FAILURE) {
1605 		return;
1606 	}
1607 	GET_REFLECTION_OBJECT();
1608 	if (!Z_ISUNDEF(intern->obj)) {
1609 		closure_this = zend_get_closure_this_ptr(&intern->obj);
1610 		if (!Z_ISUNDEF_P(closure_this)) {
1611 			Z_ADDREF_P(closure_this);
1612 			ZVAL_OBJ(return_value, Z_OBJ_P(closure_this));
1613 		}
1614 	}
1615 }
1616 /* }}} */
1617 
1618 /* {{{ proto public ReflectionClass ReflectionFunction::getClosureScopeClass()
1619    Returns the scope associated to the closure */
ZEND_METHODnull1620 ZEND_METHOD(reflection_function, getClosureScopeClass)
1621 {
1622 	reflection_object *intern;
1623 	const zend_function *closure_func;
1624 
1625 	if (zend_parse_parameters_none() == FAILURE) {
1626 		return;
1627 	}
1628 	GET_REFLECTION_OBJECT();
1629 	if (!Z_ISUNDEF(intern->obj)) {
1630 		closure_func = zend_get_closure_method_def(&intern->obj);
1631 		if (closure_func && closure_func->common.scope) {
1632 			zend_reflection_class_factory(closure_func->common.scope, return_value);
1633 		}
1634 	}
1635 }
1636 /* }}} */
1637 
1638 /* {{{ proto public mixed ReflectionFunction::getClosure()
1639    Returns a dynamically created closure for the function */
ZEND_METHODnull1640 ZEND_METHOD(reflection_function, getClosure)
1641 {
1642 	reflection_object *intern;
1643 	zend_function *fptr;
1644 
1645 	if (zend_parse_parameters_none() == FAILURE) {
1646 		return;
1647 	}
1648 	GET_REFLECTION_OBJECT_PTR(fptr);
1649 
1650 	if (!Z_ISUNDEF(intern->obj)) {
1651 		/* Closures are immutable objects */
1652 		Z_ADDREF(intern->obj);
1653 		ZVAL_OBJ(return_value, Z_OBJ(intern->obj));
1654 	} else {
1655 		zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL);
1656 	}
1657 }
1658 /* }}} */
1659 
1660 /* {{{ proto public bool ReflectionFunction::isInternal()
1661    Returns whether this is an internal function */
ZEND_METHODnull1662 ZEND_METHOD(reflection_function, isInternal)
1663 {
1664 	reflection_object *intern;
1665 	zend_function *fptr;
1666 
1667 	if (zend_parse_parameters_none() == FAILURE) {
1668 		return;
1669 	}
1670 	GET_REFLECTION_OBJECT_PTR(fptr);
1671 	RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION);
1672 }
1673 /* }}} */
1674 
1675 /* {{{ proto public bool ReflectionFunction::isUserDefined()
1676    Returns whether this is a user-defined function */
ZEND_METHODnull1677 ZEND_METHOD(reflection_function, isUserDefined)
1678 {
1679 	reflection_object *intern;
1680 	zend_function *fptr;
1681 
1682 	if (zend_parse_parameters_none() == FAILURE) {
1683 		return;
1684 	}
1685 	GET_REFLECTION_OBJECT_PTR(fptr);
1686 	RETURN_BOOL(fptr->type == ZEND_USER_FUNCTION);
1687 }
1688 /* }}} */
1689 
1690 /* {{{ proto public bool ReflectionFunction::isDisabled()
1691    Returns whether this function has been disabled or not */
ZEND_METHODnull1692 ZEND_METHOD(reflection_function, isDisabled)
1693 {
1694 	reflection_object *intern;
1695 	zend_function *fptr;
1696 
1697 	GET_REFLECTION_OBJECT_PTR(fptr);
1698 	RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.handler == zif_display_disabled_function);
1699 }
1700 /* }}} */
1701 
1702 /* {{{ proto public string ReflectionFunction::getFileName()
1703    Returns the filename of the file this function was declared in */
ZEND_METHODnull1704 ZEND_METHOD(reflection_function, getFileName)
1705 {
1706 	reflection_object *intern;
1707 	zend_function *fptr;
1708 
1709 	if (zend_parse_parameters_none() == FAILURE) {
1710 		return;
1711 	}
1712 	GET_REFLECTION_OBJECT_PTR(fptr);
1713 	if (fptr->type == ZEND_USER_FUNCTION) {
1714 		RETURN_STR_COPY(fptr->op_array.filename);
1715 	}
1716 	RETURN_FALSE;
1717 }
1718 /* }}} */
1719 
1720 /* {{{ proto public int ReflectionFunction::getStartLine()
1721    Returns the line this function's declaration starts at */
ZEND_METHODnull1722 ZEND_METHOD(reflection_function, getStartLine)
1723 {
1724 	reflection_object *intern;
1725 	zend_function *fptr;
1726 
1727 	if (zend_parse_parameters_none() == FAILURE) {
1728 		return;
1729 	}
1730 	GET_REFLECTION_OBJECT_PTR(fptr);
1731 	if (fptr->type == ZEND_USER_FUNCTION) {
1732 		RETURN_LONG(fptr->op_array.line_start);
1733 	}
1734 	RETURN_FALSE;
1735 }
1736 /* }}} */
1737 
1738 /* {{{ proto public int ReflectionFunction::getEndLine()
1739    Returns the line this function's declaration ends at */
ZEND_METHODnull1740 ZEND_METHOD(reflection_function, getEndLine)
1741 {
1742 	reflection_object *intern;
1743 	zend_function *fptr;
1744 
1745 	if (zend_parse_parameters_none() == FAILURE) {
1746 		return;
1747 	}
1748 	GET_REFLECTION_OBJECT_PTR(fptr);
1749 	if (fptr->type == ZEND_USER_FUNCTION) {
1750 		RETURN_LONG(fptr->op_array.line_end);
1751 	}
1752 	RETURN_FALSE;
1753 }
1754 /* }}} */
1755 
1756 /* {{{ proto public string ReflectionFunction::getDocComment()
1757    Returns the doc comment for this function */
ZEND_METHODnull1758 ZEND_METHOD(reflection_function, getDocComment)
1759 {
1760 	reflection_object *intern;
1761 	zend_function *fptr;
1762 
1763 	if (zend_parse_parameters_none() == FAILURE) {
1764 		return;
1765 	}
1766 	GET_REFLECTION_OBJECT_PTR(fptr);
1767 	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
1768 		RETURN_STR_COPY(fptr->op_array.doc_comment);
1769 	}
1770 	RETURN_FALSE;
1771 }
1772 /* }}} */
1773 
1774 /* {{{ proto public array ReflectionFunction::getStaticVariables()
1775    Returns an associative array containing this function's static variables and their values */
ZEND_METHODnull1776 ZEND_METHOD(reflection_function, getStaticVariables)
1777 {
1778 	reflection_object *intern;
1779 	zend_function *fptr;
1780 	zval *val;
1781 
1782 	if (zend_parse_parameters_none() == FAILURE) {
1783 		return;
1784 	}
1785 	GET_REFLECTION_OBJECT_PTR(fptr);
1786 
1787 	/* Return an empty array in case no static variables exist */
1788 	if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
1789 		HashTable *ht;
1790 
1791 		array_init(return_value);
1792 		ht = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
1793 		if (!ht) {
1794 			ZEND_ASSERT(fptr->op_array.fn_flags & ZEND_ACC_IMMUTABLE);
1795 			ht = zend_array_dup(fptr->op_array.static_variables);
1796 			ZEND_MAP_PTR_SET(fptr->op_array.static_variables_ptr, ht);
1797 		}
1798 		ZEND_HASH_FOREACH_VAL(ht, val) {
1799 			if (UNEXPECTED(zval_update_constant_ex(val, fptr->common.scope) != SUCCESS)) {
1800 				return;
1801 			}
1802 		} ZEND_HASH_FOREACH_END();
1803 		zend_hash_copy(Z_ARRVAL_P(return_value), ht, zval_add_ref);
1804 	} else {
1805 		RETURN_EMPTY_ARRAY();
1806 	}
1807 }
1808 /* }}} */
1809 
1810 /* {{{ proto public mixed ReflectionFunction::invoke([mixed* args])
1811    Invokes the function */
ZEND_METHODnull1812 ZEND_METHOD(reflection_function, invoke)
1813 {
1814 	zval retval;
1815 	zval *params = NULL;
1816 	int result, num_args = 0;
1817 	zend_fcall_info fci;
1818 	zend_fcall_info_cache fcc;
1819 	reflection_object *intern;
1820 	zend_function *fptr;
1821 
1822 	GET_REFLECTION_OBJECT_PTR(fptr);
1823 
1824 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "*", &params, &num_args) == FAILURE) {
1825 		return;
1826 	}
1827 
1828 	fci.size = sizeof(fci);
1829 	ZVAL_UNDEF(&fci.function_name);
1830 	fci.object = NULL;
1831 	fci.retval = &retval;
1832 	fci.param_count = num_args;
1833 	fci.params = params;
1834 	fci.no_separation = 1;
1835 
1836 	fcc.function_handler = fptr;
1837 	fcc.called_scope = NULL;
1838 	fcc.object = NULL;
1839 
1840 	if (!Z_ISUNDEF(intern->obj)) {
1841 		Z_OBJ_HT(intern->obj)->get_closure(
1842 			&intern->obj, &fcc.called_scope, &fcc.function_handler, &fcc.object);
1843 	}
1844 
1845 	result = zend_call_function(&fci, &fcc);
1846 
1847 	if (result == FAILURE) {
1848 		zend_throw_exception_ex(reflection_exception_ptr, 0,
1849 			"Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name));
1850 		return;
1851 	}
1852 
1853 	if (Z_TYPE(retval) != IS_UNDEF) {
1854 		if (Z_ISREF(retval)) {
1855 			zend_unwrap_reference(&retval);
1856 		}
1857 		ZVAL_COPY_VALUE(return_value, &retval);
1858 	}
1859 }
1860 /* }}} */
1861 
1862 /* {{{ proto public mixed ReflectionFunction::invokeArgs(array args)
1863    Invokes the function and pass its arguments as array. */
ZEND_METHODnull1864 ZEND_METHOD(reflection_function, invokeArgs)
1865 {
1866 	zval retval;
1867 	zval *params, *val;
1868 	int result;
1869 	int i, argc;
1870 	zend_fcall_info fci;
1871 	zend_fcall_info_cache fcc;
1872 	reflection_object *intern;
1873 	zend_function *fptr;
1874 	zval *param_array;
1875 
1876 	GET_REFLECTION_OBJECT_PTR(fptr);
1877 
1878 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &param_array) == FAILURE) {
1879 		return;
1880 	}
1881 
1882 	argc = zend_hash_num_elements(Z_ARRVAL_P(param_array));
1883 
1884 	params = safe_emalloc(sizeof(zval), argc, 0);
1885 	argc = 0;
1886 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(param_array), val) {
1887 		ZVAL_COPY(&params[argc], val);
1888 		argc++;
1889 	} ZEND_HASH_FOREACH_END();
1890 
1891 	fci.size = sizeof(fci);
1892 	ZVAL_UNDEF(&fci.function_name);
1893 	fci.object = NULL;
1894 	fci.retval = &retval;
1895 	fci.param_count = argc;
1896 	fci.params = params;
1897 	fci.no_separation = 1;
1898 
1899 	fcc.function_handler = fptr;
1900 	fcc.called_scope = NULL;
1901 	fcc.object = NULL;
1902 
1903 	if (!Z_ISUNDEF(intern->obj)) {
1904 		Z_OBJ_HT(intern->obj)->get_closure(
1905 			&intern->obj, &fcc.called_scope, &fcc.function_handler, &fcc.object);
1906 	}
1907 
1908 	result = zend_call_function(&fci, &fcc);
1909 
1910 	for (i = 0; i < argc; i++) {
1911 		zval_ptr_dtor(&params[i]);
1912 	}
1913 	efree(params);
1914 
1915 	if (result == FAILURE) {
1916 		zend_throw_exception_ex(reflection_exception_ptr, 0,
1917 			"Invocation of function %s() failed", ZSTR_VAL(fptr->common.function_name));
1918 		return;
1919 	}
1920 
1921 	if (Z_TYPE(retval) != IS_UNDEF) {
1922 		if (Z_ISREF(retval)) {
1923 			zend_unwrap_reference(&retval);
1924 		}
1925 		ZVAL_COPY_VALUE(return_value, &retval);
1926 	}
1927 }
1928 /* }}} */
1929 
1930 /* {{{ proto public bool ReflectionFunction::returnsReference()
1931    Gets whether this function returns a reference */
ZEND_METHODnull1932 ZEND_METHOD(reflection_function, returnsReference)
1933 {
1934 	reflection_object *intern;
1935 	zend_function *fptr;
1936 
1937 	GET_REFLECTION_OBJECT_PTR(fptr);
1938 
1939 	RETURN_BOOL((fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0);
1940 }
1941 /* }}} */
1942 
1943 /* {{{ proto public bool ReflectionFunction::getNumberOfParameters()
1944    Gets the number of parameters */
ZEND_METHODnull1945 ZEND_METHOD(reflection_function, getNumberOfParameters)
1946 {
1947 	reflection_object *intern;
1948 	zend_function *fptr;
1949 	uint32_t num_args;
1950 
1951 	GET_REFLECTION_OBJECT_PTR(fptr);
1952 
1953 	num_args = fptr->common.num_args;
1954 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
1955 		num_args++;
1956 	}
1957 
1958 	RETURN_LONG(num_args);
1959 }
1960 /* }}} */
1961 
1962 /* {{{ proto public bool ReflectionFunction::getNumberOfRequiredParameters()
1963    Gets the number of required parameters */
ZEND_METHODnull1964 ZEND_METHOD(reflection_function, getNumberOfRequiredParameters)
1965 {
1966 	reflection_object *intern;
1967 	zend_function *fptr;
1968 
1969 	GET_REFLECTION_OBJECT_PTR(fptr);
1970 
1971 	RETURN_LONG(fptr->common.required_num_args);
1972 }
1973 /* }}} */
1974 
1975 /* {{{ proto public ReflectionParameter[] ReflectionFunction::getParameters()
1976    Returns an array of parameter objects for this function */
ZEND_METHODnull1977 ZEND_METHOD(reflection_function, getParameters)
1978 {
1979 	reflection_object *intern;
1980 	zend_function *fptr;
1981 	uint32_t i, num_args;
1982 	struct _zend_arg_info *arg_info;
1983 
1984 	GET_REFLECTION_OBJECT_PTR(fptr);
1985 
1986 	arg_info= fptr->common.arg_info;
1987 	num_args = fptr->common.num_args;
1988 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
1989 		num_args++;
1990 	}
1991 
1992 	if (!num_args) {
1993 		RETURN_EMPTY_ARRAY();
1994 	}
1995 
1996 	array_init(return_value);
1997 	for (i = 0; i < num_args; i++) {
1998 		zval parameter;
1999 
2000 		reflection_parameter_factory(
2001 			_copy_function(fptr),
2002 			Z_ISUNDEF(intern->obj) ? NULL : &intern->obj,
2003 			arg_info,
2004 			i,
2005 			i < fptr->common.required_num_args,
2006 			&parameter
2007 		);
2008 		add_next_index_zval(return_value, &parameter);
2009 
2010 		arg_info++;
2011 	}
2012 }
2013 /* }}} */
2014 
2015 /* {{{ proto public ReflectionExtension|NULL ReflectionFunction::getExtension()
2016    Returns NULL or the extension the function belongs to */
ZEND_METHODnull2017 ZEND_METHOD(reflection_function, getExtension)
2018 {
2019 	reflection_object *intern;
2020 	zend_function *fptr;
2021 	zend_internal_function *internal;
2022 
2023 	GET_REFLECTION_OBJECT_PTR(fptr);
2024 
2025 	if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2026 		RETURN_NULL();
2027 	}
2028 
2029 	internal = (zend_internal_function *)fptr;
2030 	if (internal->module) {
2031 		reflection_extension_factory(return_value, internal->module->name);
2032 	} else {
2033 		RETURN_NULL();
2034 	}
2035 }
2036 /* }}} */
2037 
2038 /* {{{ proto public string|false ReflectionFunction::getExtensionName()
2039    Returns false or the name of the extension the function belongs to */
ZEND_METHODnull2040 ZEND_METHOD(reflection_function, getExtensionName)
2041 {
2042 	reflection_object *intern;
2043 	zend_function *fptr;
2044 	zend_internal_function *internal;
2045 
2046 	GET_REFLECTION_OBJECT_PTR(fptr);
2047 
2048 	if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2049 		RETURN_FALSE;
2050 	}
2051 
2052 	internal = (zend_internal_function *)fptr;
2053 	if (internal->module) {
2054 		RETURN_STRING(internal->module->name);
2055 	} else {
2056 		RETURN_FALSE;
2057 	}
2058 }
2059 /* }}} */
2060 
2061 /* {{{ proto public void ReflectionGenerator::__construct(object Generator) */
ZEND_METHODnull2062 ZEND_METHOD(reflection_generator, __construct)
2063 {
2064 	zval *generator, *object;
2065 	reflection_object *intern;
2066 	zend_execute_data *ex;
2067 
2068 	object = ZEND_THIS;
2069 	intern = Z_REFLECTION_P(object);
2070 
2071 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) {
2072 		return;
2073 	}
2074 
2075 	ex = ((zend_generator *) Z_OBJ_P(generator))->execute_data;
2076 	if (!ex) {
2077 		_DO_THROW("Cannot create ReflectionGenerator based on a terminated Generator");
2078 		return;
2079 	}
2080 
2081 	if (intern->ce) {
2082 		zval_ptr_dtor(&intern->obj);
2083 	}
2084 
2085 	intern->ref_type = REF_TYPE_GENERATOR;
2086 	Z_ADDREF_P(generator);
2087 	ZVAL_OBJ(&intern->obj, Z_OBJ_P(generator));
2088 	intern->ce = zend_ce_generator;
2089 }
2090 /* }}} */
2091 
2092 #define REFLECTION_CHECK_VALID_GENERATOR(ex) \
2093 	if (!ex) { \
2094 		_DO_THROW("Cannot fetch information from a terminated Generator"); \
2095 		return; \
2096 	}
2097 
2098 /* {{{ proto public array ReflectionGenerator::getTrace($options = DEBUG_BACKTRACE_PROVIDE_OBJECT) */
ZEND_METHODnull2099 ZEND_METHOD(reflection_generator, getTrace)
2100 {
2101 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
2102 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2103 	zend_generator *root_generator;
2104 	zend_execute_data *ex_backup = EG(current_execute_data);
2105 	zend_execute_data *ex = generator->execute_data;
2106 	zend_execute_data *root_prev = NULL, *cur_prev;
2107 
2108 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &options) == FAILURE) {
2109 		return;
2110 	}
2111 
2112 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2113 
2114 	root_generator = zend_generator_get_current(generator);
2115 
2116 	cur_prev = generator->execute_data->prev_execute_data;
2117 	if (generator == root_generator) {
2118 		generator->execute_data->prev_execute_data = NULL;
2119 	} else {
2120 		root_prev = root_generator->execute_data->prev_execute_data;
2121 		generator->execute_fake.prev_execute_data = NULL;
2122 		root_generator->execute_data->prev_execute_data = &generator->execute_fake;
2123 	}
2124 
2125 	EG(current_execute_data) = root_generator->execute_data;
2126 	zend_fetch_debug_backtrace(return_value, 0, options, 0);
2127 	EG(current_execute_data) = ex_backup;
2128 
2129 	root_generator->execute_data->prev_execute_data = root_prev;
2130 	generator->execute_data->prev_execute_data = cur_prev;
2131 }
2132 /* }}} */
2133 
2134 /* {{{ proto public int ReflectionGenerator::getExecutingLine() */
ZEND_METHODnull2135 ZEND_METHOD(reflection_generator, getExecutingLine)
2136 {
2137 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2138 	zend_execute_data *ex = generator->execute_data;
2139 
2140 	if (zend_parse_parameters_none() == FAILURE) {
2141 		return;
2142 	}
2143 
2144 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2145 
2146 	ZVAL_LONG(return_value, ex->opline->lineno);
2147 }
2148 /* }}} */
2149 
2150 /* {{{ proto public string ReflectionGenerator::getExecutingFile() */
ZEND_METHODnull2151 ZEND_METHOD(reflection_generator, getExecutingFile)
2152 {
2153 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2154 	zend_execute_data *ex = generator->execute_data;
2155 
2156 	if (zend_parse_parameters_none() == FAILURE) {
2157 		return;
2158 	}
2159 
2160 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2161 
2162 	ZVAL_STR_COPY(return_value, ex->func->op_array.filename);
2163 }
2164 /* }}} */
2165 
2166 /* {{{ proto public ReflectionFunctionAbstract ReflectionGenerator::getFunction() */
ZEND_METHODnull2167 ZEND_METHOD(reflection_generator, getFunction)
2168 {
2169 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2170 	zend_execute_data *ex = generator->execute_data;
2171 
2172 	if (zend_parse_parameters_none() == FAILURE) {
2173 		return;
2174 	}
2175 
2176 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2177 
2178 	if (ex->func->common.fn_flags & ZEND_ACC_CLOSURE) {
2179 		zval closure;
2180 		ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(ex->func));
2181 		reflection_function_factory(ex->func, &closure, return_value);
2182 	} else if (ex->func->op_array.scope) {
2183 		reflection_method_factory(ex->func->op_array.scope, ex->func, NULL, return_value);
2184 	} else {
2185 		reflection_function_factory(ex->func, NULL, return_value);
2186 	}
2187 }
2188 /* }}} */
2189 
2190 /* {{{ proto public object ReflectionGenerator::getThis() */
ZEND_METHODnull2191 ZEND_METHOD(reflection_generator, getThis)
2192 {
2193 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2194 	zend_execute_data *ex = generator->execute_data;
2195 
2196 	if (zend_parse_parameters_none() == FAILURE) {
2197 		return;
2198 	}
2199 
2200 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2201 
2202 	if (Z_TYPE(ex->This) == IS_OBJECT) {
2203 		Z_ADDREF(ex->This);
2204 		ZVAL_OBJ(return_value, Z_OBJ(ex->This));
2205 	} else {
2206 		ZVAL_NULL(return_value);
2207 	}
2208 }
2209 /* }}} */
2210 
2211 /* {{{ proto public Generator ReflectionGenerator::getExecutingGenerator() */
ZEND_METHODnull2212 ZEND_METHOD(reflection_generator, getExecutingGenerator)
2213 {
2214 	zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2215 	zend_execute_data *ex = generator->execute_data;
2216 	zend_generator *current;
2217 
2218 	if (zend_parse_parameters_none() == FAILURE) {
2219 		return;
2220 	}
2221 
2222 	REFLECTION_CHECK_VALID_GENERATOR(ex)
2223 
2224 	current = zend_generator_get_current(generator);
2225 	GC_ADDREF(&current->std);
2226 
2227 	ZVAL_OBJ(return_value, (zend_object *) current);
2228 }
2229 /* }}} */
2230 
2231 /* {{{ proto public static mixed ReflectionParameter::export(mixed function, mixed parameter [, bool return]) throws ReflectionException
2232    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHODnull2233 ZEND_METHOD(reflection_parameter, export)
2234 {
2235 	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_parameter_ptr, 2);
2236 }
2237 /* }}} */
2238 
2239 /* {{{ proto public void ReflectionParameter::__construct(mixed function, mixed parameter)
2240    Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHODnull2241 ZEND_METHOD(reflection_parameter, __construct)
2242 {
2243 	parameter_reference *ref;
2244 	zval *reference, *parameter;
2245 	zval *object;
2246 	zval *prop_name;
2247 	reflection_object *intern;
2248 	zend_function *fptr;
2249 	struct _zend_arg_info *arg_info;
2250 	int position;
2251 	uint32_t num_args;
2252 	zend_class_entry *ce = NULL;
2253 	zend_bool is_closure = 0;
2254 
2255 	if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "zz", &reference, &parameter) == FAILURE) {
2256 		return;
2257 	}
2258 
2259 	object = ZEND_THIS;
2260 	intern = Z_REFLECTION_P(object);
2261 
2262 	/* First, find the function */
2263 	switch (Z_TYPE_P(reference)) {
2264 		case IS_STRING:
2265 			{
2266 				zend_string *lcname = zend_string_tolower(Z_STR_P(reference));
2267 				fptr = zend_hash_find_ptr(EG(function_table), lcname);
2268 				zend_string_release(lcname);
2269 				if (!fptr) {
2270 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2271 						"Function %s() does not exist", Z_STRVAL_P(reference));
2272 					return;
2273 				}
2274 				ce = fptr->common.scope;
2275 			}
2276 			break;
2277 
2278 		case IS_ARRAY: {
2279 				zval *classref;
2280 				zval *method;
2281 				zend_string *name, *lcname;
2282 
2283 				if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
2284 					|| ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL))
2285 				{
2286 					_DO_THROW("Expected array($object, $method) or array($classname, $method)");
2287 					return;
2288 				}
2289 
2290 				if (Z_TYPE_P(classref) == IS_OBJECT) {
2291 					ce = Z_OBJCE_P(classref);
2292 				} else {
2293 					name = zval_try_get_string(classref);
2294 					if (UNEXPECTED(!name)) {
2295 						return;
2296 					}
2297 					if ((ce = zend_lookup_class(name)) == NULL) {
2298 						zend_throw_exception_ex(reflection_exception_ptr, 0,
2299 								"Class %s does not exist", ZSTR_VAL(name));
2300 						zend_string_release(name);
2301 						return;
2302 					}
2303 					zend_string_release(name);
2304 				}
2305 
2306 				name = zval_try_get_string(method);
2307 				if (UNEXPECTED(!name)) {
2308 					return;
2309 				}
2310 
2311 				lcname = zend_string_tolower(name);
2312 				if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname)
2313 					&& (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
2314 				{
2315 					/* nothing to do. don't set is_closure since is the invoke handler,
2316 					   not the closure itself */
2317 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
2318 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2319 						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZSTR_VAL(name));
2320 					zend_string_release(name);
2321 					zend_string_release(lcname);
2322 					return;
2323 				}
2324 				zend_string_release(name);
2325 				zend_string_release(lcname);
2326 			}
2327 			break;
2328 
2329 		case IS_OBJECT: {
2330 				ce = Z_OBJCE_P(reference);
2331 
2332 				if (instanceof_function(ce, zend_ce_closure)) {
2333 					fptr = (zend_function *)zend_get_closure_method_def(reference);
2334 					Z_ADDREF_P(reference);
2335 					is_closure = 1;
2336 				} else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) {
2337 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2338 						"Method %s::%s() does not exist", ZSTR_VAL(ce->name), ZEND_INVOKE_FUNC_NAME);
2339 					return;
2340 				}
2341 			}
2342 			break;
2343 
2344 		default:
2345 			_DO_THROW("The parameter class is expected to be either a string, an array(class, method) or a callable object");
2346 			return;
2347 	}
2348 
2349 	/* Now, search for the parameter */
2350 	arg_info = fptr->common.arg_info;
2351 	num_args = fptr->common.num_args;
2352 	if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2353 		num_args++;
2354 	}
2355 	if (Z_TYPE_P(parameter) == IS_LONG) {
2356 		position= (int)Z_LVAL_P(parameter);
2357 		if (position < 0 || (uint32_t)position >= num_args) {
2358 			_DO_THROW("The parameter specified by its offset could not be found");
2359 			goto failure;
2360 		}
2361 	} else {
2362 		uint32_t i;
2363 
2364 		position = -1;
2365 		if (!try_convert_to_string(parameter)) {
2366 			goto failure;
2367 		}
2368 
2369 		if (fptr->type == ZEND_INTERNAL_FUNCTION &&
2370 		    !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
2371 			for (i = 0; i < num_args; i++) {
2372 				if (arg_info[i].name) {
2373 					if (strcmp(((zend_internal_arg_info*)arg_info)[i].name, Z_STRVAL_P(parameter)) == 0) {
2374 						position = i;
2375 						break;
2376 					}
2377 
2378 				}
2379 			}
2380 		} else {
2381 			for (i = 0; i < num_args; i++) {
2382 				if (arg_info[i].name) {
2383 					if (strcmp(ZSTR_VAL(arg_info[i].name), Z_STRVAL_P(parameter)) == 0) {
2384 						position = i;
2385 						break;
2386 					}
2387 				}
2388 			}
2389 		}
2390 		if (position == -1) {
2391 			_DO_THROW("The parameter specified by its name could not be found");
2392 			goto failure;
2393 		}
2394 	}
2395 
2396 	ref = (parameter_reference*) emalloc(sizeof(parameter_reference));
2397 	ref->arg_info = &arg_info[position];
2398 	ref->offset = (uint32_t)position;
2399 	ref->required = (uint32_t)position < fptr->common.required_num_args;
2400 	ref->fptr = fptr;
2401 	/* TODO: copy fptr */
2402 	intern->ptr = ref;
2403 	intern->ref_type = REF_TYPE_PARAMETER;
2404 	intern->ce = ce;
2405 	if (reference && is_closure) {
2406 		ZVAL_COPY_VALUE(&intern->obj, reference);
2407 	}
2408 
2409 	prop_name = reflection_prop_name(object);
2410 	if (arg_info[position].name) {
2411 		if (fptr->type == ZEND_INTERNAL_FUNCTION &&
2412 		    !(fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
2413 			ZVAL_STRING(prop_name, ((zend_internal_arg_info*)arg_info)[position].name);
2414 		} else {
2415 			ZVAL_STR_COPY(prop_name, arg_info[position].name);
2416 		}
2417 	} else {
2418 		ZVAL_NULL(prop_name);
2419 	}
2420 	return;
2421 
2422 failure:
2423 	if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2424 		if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
2425 			zend_string_release_ex(fptr->common.function_name, 0);
2426 		}
2427 		zend_free_trampoline(fptr);
2428 	}
2429 	if (is_closure) {
2430 		zval_ptr_dtor(reference);
2431 	}
2432 }
2433 /* }}} */
2434 
2435 /* {{{ proto public string ReflectionParameter::__toString()
2436    Returns a string representation */
ZEND_METHODnull2437 ZEND_METHOD(reflection_parameter, __toString)
2438 {
2439 	reflection_object *intern;
2440 	parameter_reference *param;
2441 	smart_str str = {0};
2442 
2443 	if (zend_parse_parameters_none() == FAILURE) {
2444 		return;
2445 	}
2446 	GET_REFLECTION_OBJECT_PTR(param);
2447 	_parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "");
2448 	RETURN_STR(smart_str_extract(&str));
2449 }
2450 
2451 /* }}} */
2452 
2453 /* {{{ proto public string ReflectionParameter::getName()
2454    Returns this parameters's name */
ZEND_METHODnull2455 ZEND_METHOD(reflection_parameter, getName)
2456 {
2457 	if (zend_parse_parameters_none() == FAILURE) {
2458 		return;
2459 	}
2460 	_default_get_name(ZEND_THIS, return_value);
2461 }
2462 /* }}} */
2463 
2464 /* {{{ proto public ReflectionFunction ReflectionParameter::getDeclaringFunction()
2465    Returns the ReflectionFunction for the function of this parameter */
ZEND_METHODnull2466 ZEND_METHOD(reflection_parameter, getDeclaringFunction)
2467 {
2468 	reflection_object *intern;
2469 	parameter_reference *param;
2470 
2471 	if (zend_parse_parameters_none() == FAILURE) {
2472 		return;
2473 	}
2474 	GET_REFLECTION_OBJECT_PTR(param);
2475 
2476 	if (!param->fptr->common.scope) {
2477 		reflection_function_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2478 	} else {
2479 		reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2480 	}
2481 }
2482 /* }}} */
2483 
2484 /* {{{ proto public ReflectionClass|NULL ReflectionParameter::getDeclaringClass()
2485    Returns in which class this parameter is defined (not the type of the parameter) */
ZEND_METHODnull2486 ZEND_METHOD(reflection_parameter, getDeclaringClass)
2487 {
2488 	reflection_object *intern;
2489 	parameter_reference *param;
2490 
2491 	if (zend_parse_parameters_none() == FAILURE) {
2492 		return;
2493 	}
2494 	GET_REFLECTION_OBJECT_PTR(param);
2495 
2496 	if (param->fptr->common.scope) {
2497 		zend_reflection_class_factory(param->fptr->common.scope, return_value);
2498 	}
2499 }
2500 /* }}} */
2501 
2502 /* {{{ proto public ReflectionClass|NULL ReflectionParameter::getClass()
2503    Returns this parameters's class hint or NULL if there is none */
ZEND_METHODnull2504 ZEND_METHOD(reflection_parameter, getClass)
2505 {
2506 	reflection_object *intern;
2507 	parameter_reference *param;
2508 	zend_class_entry *ce;
2509 
2510 	if (zend_parse_parameters_none() == FAILURE) {
2511 		return;
2512 	}
2513 	GET_REFLECTION_OBJECT_PTR(param);
2514 
2515 	if (ZEND_TYPE_IS_CLASS(param->arg_info->type)) {
2516 		/* Class name is stored as a string, we might also get "self" or "parent"
2517 		 * - For "self", simply use the function scope. If scope is NULL then
2518 		 *   the function is global and thus self does not make any sense
2519 		 *
2520 		 * - For "parent", use the function scope's parent. If scope is NULL then
2521 		 *   the function is global and thus parent does not make any sense.
2522 		 *   If the parent is NULL then the class does not extend anything and
2523 		 *   thus parent does not make any sense, either.
2524 		 *
2525 		 * TODO: Think about moving these checks to the compiler or some sort of
2526 		 * lint-mode.
2527 		 */
2528 		zend_string *class_name;
2529 
2530 		class_name = ZEND_TYPE_NAME(param->arg_info->type);
2531 		if (0 == zend_binary_strcasecmp(ZSTR_VAL(class_name), ZSTR_LEN(class_name), "self", sizeof("self")- 1)) {
2532 			ce = param->fptr->common.scope;
2533 			if (!ce) {
2534 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2535 					"Parameter uses 'self' as type hint but function is not a class member!");
2536 				return;
2537 			}
2538 		} else if (0 == zend_binary_strcasecmp(ZSTR_VAL(class_name), ZSTR_LEN(class_name), "parent", sizeof("parent")- 1)) {
2539 			ce = param->fptr->common.scope;
2540 			if (!ce) {
2541 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2542 					"Parameter uses 'parent' as type hint but function is not a class member!");
2543 				return;
2544 			}
2545 			if (!ce->parent) {
2546 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2547 					"Parameter uses 'parent' as type hint although class does not have a parent!");
2548 				return;
2549 			}
2550 			ce = ce->parent;
2551 		} else {
2552 			ce = zend_lookup_class(class_name);
2553 			if (!ce) {
2554 				zend_throw_exception_ex(reflection_exception_ptr, 0,
2555 					"Class %s does not exist", ZSTR_VAL(class_name));
2556 				return;
2557 			}
2558 		}
2559 		zend_reflection_class_factory(ce, return_value);
2560 	}
2561 }
2562 /* }}} */
2563 
2564 /* {{{ proto public bool ReflectionParameter::hasType()
2565    Returns whether parameter has a type */
ZEND_METHODnull2566 ZEND_METHOD(reflection_parameter, hasType)
2567 {
2568 	reflection_object *intern;
2569 	parameter_reference *param;
2570 
2571 	if (zend_parse_parameters_none() == FAILURE) {
2572 		return;
2573 	}
2574 	GET_REFLECTION_OBJECT_PTR(param);
2575 
2576 	RETVAL_BOOL(ZEND_TYPE_IS_SET(param->arg_info->type));
2577 }
2578 /* }}} */
2579 
2580 /* {{{ proto public ReflectionType ReflectionParameter::getType()
2581    Returns the type associated with the parameter */
ZEND_METHODnull2582 ZEND_METHOD(reflection_parameter, getType)
2583 {
2584 	reflection_object *intern;
2585 	parameter_reference *param;
2586 
2587 	if (zend_parse_parameters_none() == FAILURE) {
2588 		return;
2589 	}
2590 	GET_REFLECTION_OBJECT_PTR(param);
2591 
2592 	if (!ZEND_TYPE_IS_SET(param->arg_info->type)) {
2593 		RETURN_NULL();
2594 	}
2595 	reflection_type_factory(param->arg_info->type, return_value);
2596 }
2597 /* }}} */
2598 
2599 /* {{{ proto public bool ReflectionParameter::isArray()
2600    Returns whether parameter MUST be an array */
ZEND_METHODnull2601 ZEND_METHOD(reflection_parameter, isArray)
2602 {
2603 	reflection_object *intern;
2604 	parameter_reference *param;
2605 
2606 	if (zend_parse_parameters_none() == FAILURE) {
2607 		return;
2608 	}
2609 	GET_REFLECTION_OBJECT_PTR(param);
2610 
2611 	RETVAL_BOOL(ZEND_TYPE_CODE(param->arg_info->type) == IS_ARRAY);
2612 }
2613 /* }}} */
2614 
2615 /* {{{ proto public bool ReflectionParameter::isCallable()
2616    Returns whether parameter MUST be callable */
ZEND_METHODnull2617 ZEND_METHOD(reflection_parameter, isCallable)
2618 {
2619 	reflection_object *intern;
2620 	parameter_reference *param;
2621 
2622 	if (zend_parse_parameters_none() == FAILURE) {
2623 		return;
2624 	}
2625 	GET_REFLECTION_OBJECT_PTR(param);
2626 
2627 	RETVAL_BOOL(ZEND_TYPE_CODE(param->arg_info->type) == IS_CALLABLE);
2628 }
2629 /* }}} */
2630 
2631 /* {{{ proto public bool ReflectionParameter::allowsNull()
2632    Returns whether NULL is allowed as this parameters's value */
ZEND_METHODnull2633 ZEND_METHOD(reflection_parameter, allowsNull)
2634 {
2635 	reflection_object *intern;
2636 	parameter_reference *param;
2637 
2638 	if (zend_parse_parameters_none() == FAILURE) {
2639 		return;
2640 	}
2641 	GET_REFLECTION_OBJECT_PTR(param);
2642 
2643 	RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->arg_info->type));
2644 }
2645 /* }}} */
2646 
2647 /* {{{ proto public bool ReflectionParameter::isPassedByReference()
2648    Returns whether this parameters is passed to by reference */
ZEND_METHODnull2649 ZEND_METHOD(reflection_parameter, isPassedByReference)
2650 {
2651 	reflection_object *intern;
2652 	parameter_reference *param;
2653 
2654 	if (zend_parse_parameters_none() == FAILURE) {
2655 		return;
2656 	}
2657 	GET_REFLECTION_OBJECT_PTR(param);
2658 
2659 	RETVAL_BOOL(param->arg_info->pass_by_reference);
2660 }
2661 /* }}} */
2662 
2663 /* {{{ proto public bool ReflectionParameter::canBePassedByValue()
2664    Returns whether this parameter can be passed by value */
ZEND_METHODnull2665 ZEND_METHOD(reflection_parameter, canBePassedByValue)
2666 {
2667 	reflection_object *intern;
2668 	parameter_reference *param;
2669 
2670 	if (zend_parse_parameters_none() == FAILURE) {
2671 		return;
2672 	}
2673 	GET_REFLECTION_OBJECT_PTR(param);
2674 
2675 	/* true if it's ZEND_SEND_BY_VAL or ZEND_SEND_PREFER_REF */
2676 	RETVAL_BOOL(param->arg_info->pass_by_reference != ZEND_SEND_BY_REF);
2677 }
2678 /* }}} */
2679 
2680 /* {{{ proto public bool ReflectionParameter::getPosition()
2681    Returns whether this parameter is an optional parameter */
ZEND_METHODnull2682 ZEND_METHOD(reflection_parameter, getPosition)
2683 {
2684 	reflection_object *intern;
2685 	parameter_reference *param;
2686 
2687 	if (zend_parse_parameters_none() == FAILURE) {
2688 		return;
2689 	}
2690 	GET_REFLECTION_OBJECT_PTR(param);
2691 
2692 	RETVAL_LONG(param->offset);
2693 }
2694 /* }}} */
2695 
2696 /* {{{ proto public bool ReflectionParameter::isOptional()
2697    Returns whether this parameter is an optional parameter */
ZEND_METHODnull2698 ZEND_METHOD(reflection_parameter, isOptional)
2699 {
2700 	reflection_object *intern;
2701 	parameter_reference *param;
2702 
2703 	if (zend_parse_parameters_none() == FAILURE) {
2704 		return;
2705 	}
2706 	GET_REFLECTION_OBJECT_PTR(param);
2707 
2708 	RETVAL_BOOL(!param->required);
2709 }
2710 /* }}} */
2711 
2712 /* {{{ proto public bool ReflectionParameter::isDefaultValueAvailable()
2713    Returns whether the default value of this parameter is available */
ZEND_METHODnull2714 ZEND_METHOD(reflection_parameter, isDefaultValueAvailable)
2715 {
2716 	reflection_object *intern;
2717 	parameter_reference *param;
2718 	zend_op *precv;
2719 
2720 	if (zend_parse_parameters_none() == FAILURE) {
2721 		return;
2722 	}
2723 	GET_REFLECTION_OBJECT_PTR(param);
2724 
2725 	if (param->fptr->type != ZEND_USER_FUNCTION)
2726 	{
2727 		RETURN_FALSE;
2728 	}
2729 
2730 	precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
2731 	if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) {
2732 		RETURN_FALSE;
2733 	}
2734 	RETURN_TRUE;
2735 }
2736 /* }}} */
2737 
2738 /* {{{ proto public bool ReflectionParameter::getDefaultValue()
2739    Returns the default value of this parameter or throws an exception */
ZEND_METHODnull2740 ZEND_METHOD(reflection_parameter, getDefaultValue)
2741 {
2742 	parameter_reference *param;
2743 	zend_op *precv;
2744 
2745 	if (zend_parse_parameters_none() == FAILURE) {
2746 		return;
2747 	}
2748 
2749 	param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2750 	if (!param) {
2751 		return;
2752 	}
2753 
2754 	precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2755 	if (!precv) {
2756 		return;
2757 	}
2758 
2759 	ZVAL_COPY(return_value, RT_CONSTANT(precv, precv->op2));
2760 	if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
2761 		zval_update_constant_ex(return_value, param->fptr->common.scope);
2762 	}
2763 }
2764 /* }}} */
2765 
2766 /* {{{ proto public bool ReflectionParameter::isDefaultValueConstant()
2767    Returns whether the default value of this parameter is constant */
ZEND_METHODnull2768 ZEND_METHOD(reflection_parameter, isDefaultValueConstant)
2769 {
2770 	zend_op *precv;
2771 	parameter_reference *param;
2772 
2773 	if (zend_parse_parameters_none() == FAILURE) {
2774 		return;
2775 	}
2776 
2777 	param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2778 	if (!param) {
2779 		RETURN_FALSE;
2780 	}
2781 
2782 	precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2783 	if (precv && Z_TYPE_P(RT_CONSTANT(precv, precv->op2)) == IS_CONSTANT_AST) {
2784 		zend_ast *ast = Z_ASTVAL_P(RT_CONSTANT(precv, precv->op2));
2785 
2786 		if (ast->kind == ZEND_AST_CONSTANT
2787 		 || ast->kind == ZEND_AST_CONSTANT_CLASS) {
2788 			RETURN_TRUE;
2789 		}
2790 	}
2791 
2792 	RETURN_FALSE;
2793 }
2794 /* }}} */
2795 
2796 /* {{{ proto public mixed ReflectionParameter::getDefaultValueConstantName()
2797    Returns the default value's constant name if default value is constant or null */
ZEND_METHODnull2798 ZEND_METHOD(reflection_parameter, getDefaultValueConstantName)
2799 {
2800 	zend_op *precv;
2801 	parameter_reference *param;
2802 
2803 	if (zend_parse_parameters_none() == FAILURE) {
2804 		return;
2805 	}
2806 
2807 	param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU);
2808 	if (!param) {
2809 		return;
2810 	}
2811 
2812 	precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param);
2813 	if (precv && Z_TYPE_P(RT_CONSTANT(precv, precv->op2)) == IS_CONSTANT_AST) {
2814 		zend_ast *ast = Z_ASTVAL_P(RT_CONSTANT(precv, precv->op2));
2815 
2816 		if (ast->kind == ZEND_AST_CONSTANT) {
2817 			RETURN_STR_COPY(zend_ast_get_constant_name(ast));
2818 		} else if (ast->kind == ZEND_AST_CONSTANT_CLASS) {
2819 			RETURN_STRINGL("__CLASS__", sizeof("__CLASS__")-1);
2820 		}
2821 	}
2822 }
2823 /* }}} */
2824 
2825 /* {{{ proto public bool ReflectionParameter::isVariadic()
2826    Returns whether this parameter is a variadic parameter */
ZEND_METHODnull2827 ZEND_METHOD(reflection_parameter, isVariadic)
2828 {
2829 	reflection_object *intern;
2830 	parameter_reference *param;
2831 
2832 	if (zend_parse_parameters_none() == FAILURE) {
2833 		return;
2834 	}
2835 	GET_REFLECTION_OBJECT_PTR(param);
2836 
2837 	RETVAL_BOOL(param->arg_info->is_variadic);
2838 }
2839 /* }}} */
2840 
2841 /* {{{ proto public bool ReflectionType::allowsNull()
2842   Returns whether parameter MAY be null */
ZEND_METHODnull2843 ZEND_METHOD(reflection_type, allowsNull)
2844 {
2845 	reflection_object *intern;
2846 	type_reference *param;
2847 
2848 	if (zend_parse_parameters_none() == FAILURE) {
2849 		return;
2850 	}
2851 	GET_REFLECTION_OBJECT_PTR(param);
2852 
2853 	RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->type));
2854 }
2855 /* }}} */
2856 
2857 /* {{{ proto public bool ReflectionType::isBuiltin()
2858   Returns whether parameter is a builtin type */
ZEND_METHODnull2859 ZEND_METHOD(reflection_type, isBuiltin)
2860 {
2861 	reflection_object *intern;
2862 	type_reference *param;
2863 
2864 	if (zend_parse_parameters_none() == FAILURE) {
2865 		return;
2866 	}
2867 	GET_REFLECTION_OBJECT_PTR(param);
2868 
2869 	RETVAL_BOOL(ZEND_TYPE_IS_CODE(param->type));
2870 }
2871 /* }}} */
2872 
2873 /* {{{ reflection_type_name */
reflection_type_name(type_reference *param)2874 static zend_string *reflection_type_name(type_reference *param) {
2875 	if (ZEND_TYPE_IS_NAME(param->type)) {
2876 		return zend_string_copy(ZEND_TYPE_NAME(param->type));
2877 	} else if (ZEND_TYPE_IS_CE(param->type)) {
2878 		return zend_string_copy(ZEND_TYPE_CE(param->type)->name);
2879 	} else {
2880 		char *name = zend_get_type_by_const(ZEND_TYPE_CODE(param->type));
2881 		return zend_string_init(name, strlen(name), 0);
2882 	}
2883 }
2884 /* }}} */
2885 
2886 /* {{{ proto public string ReflectionType::__toString()
2887    Return the text of the type hint */
ZEND_METHODnull2888 ZEND_METHOD(reflection_type, __toString)
2889 {
2890 	reflection_object *intern;
2891 	type_reference *param;
2892 
2893 	if (zend_parse_parameters_none() == FAILURE) {
2894 		return;
2895 	}
2896 	GET_REFLECTION_OBJECT_PTR(param);
2897 
2898 	RETURN_STR(reflection_type_name(param));
2899 }
2900 /* }}} */
2901 
2902 /* {{{ proto public string ReflectionNamedType::getName()
2903  Return the text of the type hint */
ZEND_METHODnull2904 ZEND_METHOD(reflection_named_type, getName)
2905 {
2906 	reflection_object *intern;
2907 	type_reference *param;
2908 
2909 	if (zend_parse_parameters_none() == FAILURE) {
2910 		return;
2911 	}
2912 	GET_REFLECTION_OBJECT_PTR(param);
2913 
2914 	RETURN_STR(reflection_type_name(param));
2915 }
2916 /* }}} */
2917 
2918 /* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
2919    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHODnull2920 ZEND_METHOD(reflection_method, export)
2921 {
2922 	_reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_method_ptr, 2);
2923 }
2924 /* }}} */
2925 
2926 /* {{{ proto public void ReflectionMethod::__construct(mixed class_or_method [, string name])
2927    Constructor. Throws an Exception in case the given method does not exist */
ZEND_METHODnull2928 ZEND_METHOD(reflection_method, __construct)
2929 {
2930 	zval *classname;
2931 	zval *object, *orig_obj;
2932 	reflection_object *intern;
2933 	char *lcname;
2934 	zend_class_entry *ce;
2935 	zend_function *mptr;
2936 	char *name_str, *tmp;
2937 	size_t name_len, tmp_len;
2938 	zval ztmp;
2939 
2940 	if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "zs", &classname, &name_str, &name_len) == FAILURE) {
2941 		if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "s", &name_str, &name_len) == FAILURE) {
2942 			return;
2943 		}
2944 
2945 		if ((tmp = strstr(name_str, "::")) == NULL) {
2946 			zend_throw_exception_ex(reflection_exception_ptr, 0,
2947 				"Invalid method name %s", name_str);
2948 			return;
2949 		}
2950 		classname = &ztmp;
2951 		tmp_len = tmp - name_str;
2952 		ZVAL_STRINGL(classname, name_str, tmp_len);
2953 		name_len = name_len - (tmp_len + 2);
2954 		name_str = tmp + 2;
2955 		orig_obj = NULL;
2956 	} else if (Z_TYPE_P(classname) == IS_OBJECT) {
2957 		orig_obj = classname;
2958 	} else {
2959 		orig_obj = NULL;
2960 	}
2961 
2962 	object = ZEND_THIS;
2963 	intern = Z_REFLECTION_P(object);
2964 
2965 	/* Find the class entry */
2966 	switch (Z_TYPE_P(classname)) {
2967 		case IS_STRING:
2968 			if ((ce = zend_lookup_class(Z_STR_P(classname))) == NULL) {
2969 				if (!EG(exception)) {
2970 					zend_throw_exception_ex(reflection_exception_ptr, 0,
2971 							"Class %s does not exist", Z_STRVAL_P(classname));
2972 				}
2973 				if (classname == &ztmp) {
2974 					zval_ptr_dtor_str(&ztmp);
2975 				}
2976 				return;
2977 			}
2978 			break;
2979 
2980 		case IS_OBJECT:
2981 			ce = Z_OBJCE_P(classname);
2982 			break;
2983 
2984 		default:
2985 			if (classname == &ztmp) {
2986 				zval_ptr_dtor_str(&ztmp);
2987 			}
2988 			_DO_THROW("The parameter class is expected to be either a string or an object");
2989 			return;
2990 	}
2991 
2992 	if (classname == &ztmp) {
2993 		zval_ptr_dtor_str(&ztmp);
2994 	}
2995 
2996 	lcname = zend_str_tolower_dup(name_str, name_len);
2997 
2998 	if (ce == zend_ce_closure && orig_obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
2999 		&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3000 		&& (mptr = zend_get_closure_invoke_method(Z_OBJ_P(orig_obj))) != NULL)
3001 	{
3002 		/* do nothing, mptr already set */
3003 	} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, name_len)) == NULL) {
3004 		efree(lcname);
3005 		zend_throw_exception_ex(reflection_exception_ptr, 0,
3006 			"Method %s::%s() does not exist", ZSTR_VAL(ce->name), name_str);
3007 		return;
3008 	}
3009 	efree(lcname);
3010 
3011 	ZVAL_STR_COPY(reflection_prop_name(object), mptr->common.function_name);
3012 	ZVAL_STR_COPY(reflection_prop_class(object), mptr->common.scope->name);
3013 	intern->ptr = mptr;
3014 	intern->ref_type = REF_TYPE_FUNCTION;
3015 	intern->ce = ce;
3016 }
3017 /* }}} */
3018 
3019 /* {{{ proto public string ReflectionMethod::__toString()
3020    Returns a string representation */
ZEND_METHODnull3021 ZEND_METHOD(reflection_method, __toString)
3022 {
3023 	reflection_object *intern;
3024 	zend_function *mptr;
3025 	smart_str str = {0};
3026 
3027 	if (zend_parse_parameters_none() == FAILURE) {
3028 		return;
3029 	}
3030 	GET_REFLECTION_OBJECT_PTR(mptr);
3031 	_function_string(&str, mptr, intern->ce, "");
3032 	RETURN_STR(smart_str_extract(&str));
3033 }
3034 /* }}} */
3035 
3036 /* {{{ proto public mixed ReflectionMethod::getClosure([mixed object])
3037    Invokes the function */
ZEND_METHODnull3038 ZEND_METHOD(reflection_method, getClosure)
3039 {
3040 	reflection_object *intern;
3041 	zval *obj;
3042 	zend_function *mptr;
3043 
3044 	GET_REFLECTION_OBJECT_PTR(mptr);
3045 
3046 	if (mptr->common.fn_flags & ZEND_ACC_STATIC)  {
3047 		zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
3048 	} else {
3049 		if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &obj) == FAILURE) {
3050 			return;
3051 		}
3052 
3053 		if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope)) {
3054 			_DO_THROW("Given object is not an instance of the class this method was declared in");
3055 			return;
3056 		}
3057 
3058 		/* This is an original closure object and __invoke is to be called. */
3059 		if (Z_OBJCE_P(obj) == zend_ce_closure &&
3060 			(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
3061 		{
3062 			Z_ADDREF_P(obj);
3063 			ZVAL_OBJ(return_value, Z_OBJ_P(obj));
3064 		} else {
3065 			zend_create_fake_closure(