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