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