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