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