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