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