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