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