1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Timm Friebe <thekid@thekid.de> |
16 : | George Schlossnagle <george@omniti.com> |
17 : | Andrei Zmievski <andrei@gravitonic.com> |
18 : | Marcus Boerger <helly@php.net> |
19 : | Johannes Schlueter <johannes@php.net> |
20 : +----------------------------------------------------------------------+
21 : */
22 :
23 : /* $Id: php_reflection.c 290515 2009-11-11 18:52:12Z felipe $ */
24 :
25 : #ifdef HAVE_CONFIG_H
26 : #include "config.h"
27 : #endif
28 :
29 : #include "php.h"
30 : #include "php_ini.h"
31 : #include "php_reflection.h"
32 : #include "ext/standard/info.h"
33 :
34 : #include "zend.h"
35 : #include "zend_API.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 :
43 : /* Undefine "getParameters" macro defined in "main/php3_compat.h" */
44 : #ifdef getParameters
45 : # undef getParameters
46 : #endif
47 :
48 : /* Class entry pointers */
49 : PHPAPI zend_class_entry *reflector_ptr;
50 : PHPAPI zend_class_entry *reflection_exception_ptr;
51 : PHPAPI zend_class_entry *reflection_ptr;
52 : PHPAPI zend_class_entry *reflection_function_abstract_ptr;
53 : PHPAPI zend_class_entry *reflection_function_ptr;
54 : PHPAPI zend_class_entry *reflection_parameter_ptr;
55 : PHPAPI zend_class_entry *reflection_class_ptr;
56 : PHPAPI zend_class_entry *reflection_object_ptr;
57 : PHPAPI zend_class_entry *reflection_method_ptr;
58 : PHPAPI zend_class_entry *reflection_property_ptr;
59 : PHPAPI zend_class_entry *reflection_extension_ptr;
60 :
61 : #if MBO_0
62 : ZEND_BEGIN_MODULE_GLOBALS(reflection)
63 : int dummy;
64 : ZEND_END_MODULE_GLOBALS(reflection)
65 :
66 : #ifdef ZTS
67 : # define REFLECTION_G(v) \
68 : TSRMG(reflection_globals_id, zend_reflection_globals*, v)
69 : extern int reflection_globals_id;
70 : #else
71 : # define REFLECTION_G(v) (reflection_globals.v)
72 : extern zend_reflection_globals reflectionglobals;
73 : #endif
74 :
75 : ZEND_DECLARE_MODULE_GLOBALS(reflection)
76 : #endif /* MBO_0 */
77 :
78 : /* Method macros */
79 :
80 : #define METHOD_NOTSTATIC(ce) \
81 : if (!this_ptr || !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) { \
82 : zend_error(E_ERROR, "%s() cannot be called statically", get_active_function_name(TSRMLS_C)); \
83 : return; \
84 : } \
85 :
86 : /* Exception throwing macro */
87 : #define _DO_THROW(msg) \
88 : zend_throw_exception(reflection_exception_ptr, msg, 0 TSRMLS_CC); \
89 : return; \
90 :
91 : #define RETURN_ON_EXCEPTION \
92 : if (EG(exception) && Z_OBJCE_P(EG(exception)) == reflection_exception_ptr) { \
93 : return; \
94 : }
95 :
96 : #define GET_REFLECTION_OBJECT_PTR(target) \
97 : intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC); \
98 : if (intern == NULL || intern->ptr == NULL) { \
99 : RETURN_ON_EXCEPTION \
100 : zend_error(E_ERROR, "Internal error: Failed to retrieve the reflection object"); \
101 : } \
102 : target = intern->ptr; \
103 :
104 : /* Class constants */
105 : #define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value) \
106 : zend_declare_class_constant_long(reflection_ ## class_name ## _ptr, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
107 :
108 : /* {{{ Smart string functions */
109 : typedef struct _string {
110 : char *string;
111 : int len;
112 : int alloced;
113 : } string;
114 :
115 : static void string_init(string *str)
116 1021 : {
117 1021 : str->string = (char *) emalloc(1024);
118 1021 : str->len = 1;
119 1021 : str->alloced = 1024;
120 1021 : *str->string = '\0';
121 1021 : }
122 :
123 : static string *string_printf(string *str, const char *format, ...)
124 12784 : {
125 : int len;
126 : va_list arg;
127 : char *s_tmp;
128 :
129 12784 : va_start(arg, format);
130 12784 : len = zend_vspprintf(&s_tmp, 0, format, arg);
131 12784 : if (len) {
132 12784 : register int nlen = (str->len + len + (1024 - 1)) & ~(1024 - 1);
133 12784 : if (str->alloced < nlen) {
134 78 : str->alloced = nlen;
135 78 : str->string = erealloc(str->string, str->alloced);
136 : }
137 12784 : memcpy(str->string + str->len - 1, s_tmp, len + 1);
138 12784 : str->len += len;
139 : }
140 12784 : efree(s_tmp);
141 12784 : va_end(arg);
142 12784 : return str;
143 : }
144 :
145 : static string *string_write(string *str, char *buf, int len)
146 1944 : {
147 1944 : register int nlen = (str->len + len + (1024 - 1)) & ~(1024 - 1);
148 1944 : if (str->alloced < nlen) {
149 30 : str->alloced = nlen;
150 30 : str->string = erealloc(str->string, str->alloced);
151 : }
152 1944 : memcpy(str->string + str->len - 1, buf, len);
153 1944 : str->len += len;
154 1944 : str->string[str->len - 1] = '\0';
155 1944 : return str;
156 : }
157 :
158 : static string *string_append(string *str, string *append)
159 51 : {
160 51 : if (append->len > 1) {
161 45 : string_write(str, append->string, append->len - 1);
162 : }
163 51 : return str;
164 : }
165 :
166 : static void string_free(string *str)
167 827 : {
168 827 : efree(str->string);
169 827 : str->len = 0;
170 827 : str->alloced = 0;
171 827 : str->string = NULL;
172 827 : }
173 : /* }}} */
174 :
175 : /* Struct for properties */
176 : typedef struct _property_reference {
177 : zend_class_entry *ce;
178 : zend_property_info prop;
179 : } property_reference;
180 :
181 : /* Struct for parameters */
182 : typedef struct _parameter_reference {
183 : zend_uint offset;
184 : zend_uint required;
185 : struct _zend_arg_info *arg_info;
186 : zend_function *fptr;
187 : } parameter_reference;
188 :
189 : typedef enum {
190 : REF_TYPE_OTHER, /* Must be 0 */
191 : REF_TYPE_FUNCTION,
192 : REF_TYPE_PARAMETER,
193 : REF_TYPE_PROPERTY
194 : } reflection_type_t;
195 :
196 : /* Struct for reflection objects */
197 : typedef struct {
198 : zend_object zo;
199 : void *ptr;
200 : reflection_type_t ref_type;
201 : zval *obj;
202 : zend_class_entry *ce;
203 : unsigned int ignore_visibility:1;
204 : } reflection_object;
205 :
206 : static zend_object_handlers reflection_object_handlers;
207 :
208 : static void _default_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC)
209 408 : {
210 : zval **value;
211 :
212 408 : if (zend_hash_find(Z_OBJPROP_P(object), name, name_len, (void **) &value) == FAILURE) {
213 0 : RETURN_FALSE;
214 : }
215 :
216 408 : *return_value = **value;
217 408 : zval_copy_ctor(return_value);
218 408 : INIT_PZVAL(return_value);
219 : }
220 :
221 : #ifdef ilia_0
222 : static void _default_lookup_entry(zval *object, char *name, int name_len, zval **return_value TSRMLS_DC) /* {{{ */
223 : {
224 : zval **value;
225 :
226 : if (zend_hash_find(Z_OBJPROP_P(object), name, name_len, (void **) &value) == FAILURE) {
227 : *return_value = NULL;
228 : } else {
229 : *return_value = *value;
230 : }
231 : }
232 : /* }}} */
233 : #endif
234 :
235 : static void reflection_register_implement(zend_class_entry *class_entry, zend_class_entry *interface_entry TSRMLS_DC)
236 88165 : {
237 88165 : zend_uint num_interfaces = ++class_entry->num_interfaces;
238 :
239 88165 : class_entry->interfaces = (zend_class_entry **) realloc(class_entry->interfaces, sizeof(zend_class_entry *) * num_interfaces);
240 88165 : class_entry->interfaces[num_interfaces - 1] = interface_entry;
241 88165 : }
242 :
243 : static zend_function *_copy_function(zend_function *fptr TSRMLS_DC) /* {{{ */
244 75 : {
245 75 : if (fptr
246 : && fptr->type == ZEND_INTERNAL_FUNCTION
247 : && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
248 : {
249 : zend_function *copy_fptr;
250 4 : copy_fptr = emalloc(sizeof(zend_function));
251 4 : memcpy(copy_fptr, fptr, sizeof(zend_function));
252 4 : copy_fptr->internal_function.function_name = estrdup(fptr->internal_function.function_name);
253 4 : return copy_fptr;
254 : } else {
255 : /* no copy needed */
256 71 : return fptr;
257 : }
258 : }
259 : /* }}} */
260 :
261 : static void _free_function(zend_function *fptr TSRMLS_DC) /* {{{ */
262 1707 : {
263 1707 : if (fptr
264 : && fptr->type == ZEND_INTERNAL_FUNCTION
265 : && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
266 : {
267 14 : efree(fptr->internal_function.function_name);
268 14 : efree(fptr);
269 : }
270 1707 : }
271 : /* }}} */
272 :
273 : static void reflection_free_objects_storage(void *object TSRMLS_DC)
274 2048 : {
275 2048 : reflection_object *intern = (reflection_object *) object;
276 : parameter_reference *reference;
277 :
278 2048 : if (intern->ptr) {
279 1976 : switch (intern->ref_type) {
280 : case REF_TYPE_PARAMETER:
281 88 : reference = (parameter_reference*)intern->ptr;
282 88 : _free_function(reference->fptr TSRMLS_CC);
283 88 : efree(intern->ptr);
284 88 : break;
285 : case REF_TYPE_FUNCTION:
286 1076 : _free_function(intern->ptr TSRMLS_CC);
287 1076 : break;
288 : case REF_TYPE_PROPERTY:
289 216 : efree(intern->ptr);
290 : break;
291 : case REF_TYPE_OTHER:
292 : break;
293 : }
294 : }
295 2048 : intern->ptr = NULL;
296 2048 : if (intern->obj) {
297 92 : zval_ptr_dtor(&intern->obj);
298 : }
299 2048 : zend_objects_free_object_storage(object TSRMLS_CC);
300 2048 : }
301 :
302 : static zend_object_value reflection_objects_new(zend_class_entry *class_type TSRMLS_DC)
303 2048 : {
304 : zval tmp;
305 : zend_object_value retval;
306 : reflection_object *intern;
307 :
308 2048 : intern = ecalloc(1, sizeof(reflection_object));
309 2048 : intern->zo.ce = class_type;
310 :
311 2048 : zend_object_std_init(&intern->zo, class_type TSRMLS_CC);
312 2048 : zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
313 2048 : retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, NULL TSRMLS_CC);
314 2048 : retval.handlers = &reflection_object_handlers;
315 2048 : return retval;
316 : }
317 :
318 : static zval * reflection_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
319 1145 : {
320 1145 : if (!object) {
321 0 : ALLOC_ZVAL(object);
322 : }
323 1145 : Z_TYPE_P(object) = IS_OBJECT;
324 1145 : object_init_ex(object, pce);
325 1145 : Z_SET_REFCOUNT_P(object, 1);
326 1145 : Z_SET_ISREF_P(object);
327 1145 : return object;
328 : }
329 :
330 : static void _const_string(string *str, char *name, zval *value, char *indent TSRMLS_DC);
331 : static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char *indent TSRMLS_DC);
332 : static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent TSRMLS_DC);
333 : static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC);
334 : static void _extension_string(string *str, zend_module_entry *module, char *indent TSRMLS_DC);
335 :
336 : /* {{{ _class_string */
337 : static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC)
338 53 : {
339 53 : int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
340 : string sub_indent;
341 :
342 53 : string_init(&sub_indent);
343 53 : string_printf(&sub_indent, "%s ", indent);
344 :
345 : /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
346 53 : if (ce->type == ZEND_USER_CLASS && ce->doc_comment) {
347 0 : string_printf(str, "%s%s", indent, ce->doc_comment);
348 0 : string_write(str, "\n", 1);
349 : }
350 :
351 53 : if (obj) {
352 7 : string_printf(str, "%sObject of class [ ", indent);
353 : } else {
354 46 : string_printf(str, "%s%s [ ", indent, (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : "Class");
355 : }
356 53 : string_printf(str, (ce->type == ZEND_USER_CLASS) ? "<user" : "<internal");
357 53 : if (ce->module) {
358 29 : string_printf(str, ":%s", ce->module->name);
359 : }
360 53 : string_printf(str, "> ");
361 53 : if (ce->get_iterator != NULL) {
362 0 : string_printf(str, "<iterateable> ");
363 : }
364 53 : if (ce->ce_flags & ZEND_ACC_INTERFACE) {
365 3 : string_printf(str, "interface ");
366 : } else {
367 50 : if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
368 2 : string_printf(str, "abstract ");
369 : }
370 50 : if (ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
371 0 : string_printf(str, "final ");
372 : }
373 50 : string_printf(str, "class ");
374 : }
375 53 : string_printf(str, "%s", ce->name);
376 53 : if (ce->parent) {
377 21 : string_printf(str, " extends %s", ce->parent->name);
378 : }
379 :
380 53 : if (ce->num_interfaces) {
381 : zend_uint i;
382 :
383 17 : if (ce->ce_flags & ZEND_ACC_INTERFACE) {
384 0 : string_printf(str, " extends %s", ce->interfaces[0]->name);
385 : } else {
386 17 : string_printf(str, " implements %s", ce->interfaces[0]->name);
387 : }
388 17 : for (i = 1; i < ce->num_interfaces; ++i) {
389 0 : string_printf(str, ", %s", ce->interfaces[i]->name);
390 : }
391 : }
392 53 : string_printf(str, " ] {\n");
393 :
394 : /* The information where a class is declared is only available for user classes */
395 53 : if (ce->type == ZEND_USER_CLASS) {
396 24 : string_printf(str, "%s @@ %s %d-%d\n", indent, ce->filename,
397 : ce->line_start, ce->line_end);
398 : }
399 :
400 : /* Constants */
401 : if (&ce->constants_table) {
402 53 : zend_hash_apply_with_argument(&ce->constants_table, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC);
403 53 : string_printf(str, "\n");
404 53 : count = zend_hash_num_elements(&ce->constants_table);
405 53 : string_printf(str, "%s - Constants [%d] {\n", indent, count);
406 53 : if (count > 0) {
407 : HashPosition pos;
408 : zval **value;
409 : char *key;
410 : uint key_len;
411 : ulong num_index;
412 :
413 14 : zend_hash_internal_pointer_reset_ex(&ce->constants_table, &pos);
414 :
415 72 : while (zend_hash_get_current_data_ex(&ce->constants_table, (void **) &value, &pos) == SUCCESS) {
416 44 : zend_hash_get_current_key_ex(&ce->constants_table, &key, &key_len, &num_index, 0, &pos);
417 :
418 44 : _const_string(str, key, *value, indent TSRMLS_CC);
419 44 : zend_hash_move_forward_ex(&ce->constants_table, &pos);
420 : }
421 : }
422 53 : string_printf(str, "%s }\n", indent);
423 : }
424 :
425 : /* Static properties */
426 : if (&ce->properties_info) {
427 : /* counting static properties */
428 53 : count = zend_hash_num_elements(&ce->properties_info);
429 53 : if (count > 0) {
430 : HashPosition pos;
431 : zend_property_info *prop;
432 :
433 30 : zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
434 :
435 118 : while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
436 58 : if(prop->flags & ZEND_ACC_SHADOW) {
437 11 : count_shadow_props++;
438 47 : } else if (prop->flags & ZEND_ACC_STATIC) {
439 3 : count_static_props++;
440 : }
441 58 : zend_hash_move_forward_ex(&ce->properties_info, &pos);
442 : }
443 : }
444 :
445 : /* static properties */
446 53 : string_printf(str, "\n%s - Static properties [%d] {\n", indent, count_static_props);
447 53 : if (count_static_props > 0) {
448 : HashPosition pos;
449 : zend_property_info *prop;
450 :
451 2 : zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
452 :
453 9 : while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
454 5 : if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) {
455 3 : _property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
456 : }
457 :
458 5 : zend_hash_move_forward_ex(&ce->properties_info, &pos);
459 : }
460 : }
461 53 : string_printf(str, "%s }\n", indent);
462 : }
463 :
464 : /* Static methods */
465 : if (&ce->function_table) {
466 : /* counting static methods */
467 53 : count = zend_hash_num_elements(&ce->function_table);
468 53 : if (count > 0) {
469 : HashPosition pos;
470 : zend_function *mptr;
471 :
472 42 : zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
473 :
474 660 : while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
475 576 : if (mptr->common.fn_flags & ZEND_ACC_STATIC
476 : && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
477 : {
478 21 : count_static_funcs++;
479 : }
480 576 : zend_hash_move_forward_ex(&ce->function_table, &pos);
481 : }
482 : }
483 :
484 : /* static methods */
485 53 : string_printf(str, "\n%s - Static methods [%d] {", indent, count_static_funcs);
486 53 : if (count_static_funcs > 0) {
487 : HashPosition pos;
488 : zend_function *mptr;
489 :
490 19 : zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
491 :
492 480 : while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
493 442 : if (mptr->common.fn_flags & ZEND_ACC_STATIC
494 : && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
495 : {
496 21 : string_printf(str, "\n");
497 21 : _function_string(str, mptr, ce, sub_indent.string TSRMLS_CC);
498 : }
499 442 : zend_hash_move_forward_ex(&ce->function_table, &pos);
500 : }
501 : } else {
502 34 : string_printf(str, "\n");
503 : }
504 53 : string_printf(str, "%s }\n", indent);
505 : }
506 :
507 : /* Default/Implicit properties */
508 : if (&ce->properties_info) {
509 53 : count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
510 53 : string_printf(str, "\n%s - Properties [%d] {\n", indent, count);
511 53 : if (count > 0) {
512 : HashPosition pos;
513 : zend_property_info *prop;
514 :
515 26 : zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
516 :
517 103 : while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
518 51 : if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) {
519 44 : _property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
520 : }
521 51 : zend_hash_move_forward_ex(&ce->properties_info, &pos);
522 : }
523 : }
524 53 : string_printf(str, "%s }\n", indent);
525 : }
526 :
527 53 : if (obj && Z_OBJ_HT_P(obj)->get_properties) {
528 : string dyn;
529 7 : HashTable *properties = Z_OBJ_HT_P(obj)->get_properties(obj TSRMLS_CC);
530 : HashPosition pos;
531 : zval **prop;
532 :
533 7 : string_init(&dyn);
534 7 : count = 0;
535 :
536 7 : if (properties && zend_hash_num_elements(properties)) {
537 6 : zend_hash_internal_pointer_reset_ex(properties, &pos);
538 :
539 26 : while (zend_hash_get_current_data_ex(properties, (void **) &prop, &pos) == SUCCESS) {
540 : char *prop_name;
541 : uint prop_name_size;
542 : ulong index;
543 :
544 14 : if (zend_hash_get_current_key_ex(properties, &prop_name, &prop_name_size, &index, 1, &pos) == HASH_KEY_IS_STRING) {
545 14 : if (prop_name_size && prop_name[0]) { /* skip all private and protected properties */
546 11 : if (!zend_hash_quick_exists(&ce->properties_info, prop_name, prop_name_size, zend_get_hash_value(prop_name, prop_name_size))) {
547 5 : count++;
548 5 : _property_string(&dyn, NULL, prop_name, sub_indent.string TSRMLS_CC);
549 : }
550 : }
551 14 : efree(prop_name);
552 : }
553 14 : zend_hash_move_forward_ex(properties, &pos);
554 : }
555 : }
556 :
557 7 : string_printf(str, "\n%s - Dynamic properties [%d] {\n", indent, count);
558 7 : string_append(str, &dyn);
559 7 : string_printf(str, "%s }\n", indent);
560 7 : string_free(&dyn);
561 : }
562 :
563 : /* Non static methods */
564 : if (&ce->function_table) {
565 53 : count = zend_hash_num_elements(&ce->function_table) - count_static_funcs;
566 53 : if (count > 0) {
567 : HashPosition pos;
568 : zend_function *mptr;
569 : string dyn;
570 :
571 40 : count = 0;
572 40 : string_init(&dyn);
573 40 : zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
574 :
575 652 : while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
576 572 : if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0
577 : && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
578 : {
579 : char *key;
580 : uint key_len;
581 : ulong num_index;
582 542 : uint len = strlen(mptr->common.function_name);
583 :
584 : /* Do not display old-style inherited constructors */
585 542 : if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0
586 : || mptr->common.scope == ce
587 : || zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING
588 : || zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0)
589 : {
590 : zend_function *closure;
591 : /* see if this is a closure */
592 542 : if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
593 : && memcmp(mptr->common.function_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
594 : && (closure = zend_get_closure_invoke_method(obj TSRMLS_CC)) != NULL)
595 : {
596 0 : mptr = closure;
597 : } else {
598 542 : closure = NULL;
599 : }
600 542 : string_printf(&dyn, "\n");
601 542 : _function_string(&dyn, mptr, ce, sub_indent.string TSRMLS_CC);
602 542 : count++;
603 542 : _free_function(closure TSRMLS_CC);
604 : }
605 : }
606 572 : zend_hash_move_forward_ex(&ce->function_table, &pos);
607 : }
608 40 : string_printf(str, "\n%s - Methods [%d] {", indent, count);
609 40 : if (!count) {
610 2 : string_printf(str, "\n");
611 : }
612 40 : string_append(str, &dyn);
613 40 : string_free(&dyn);
614 : } else {
615 13 : string_printf(str, "\n%s - Methods [0] {\n", indent);
616 : }
617 53 : string_printf(str, "%s }\n", indent);
618 : }
619 :
620 53 : string_printf(str, "%s}\n", indent);
621 53 : string_free(&sub_indent);
622 53 : }
623 : /* }}} */
624 :
625 : /* {{{ _const_string */
626 : static void _const_string(string *str, char *name, zval *value, char *indent TSRMLS_DC)
627 58 : {
628 : char *type;
629 : zval value_copy;
630 : int use_copy;
631 :
632 58 : type = zend_zval_type_name(value);
633 :
634 58 : zend_make_printable_zval(value, &value_copy, &use_copy);
635 58 : if (use_copy) {
636 54 : value = &value_copy;
637 : }
638 :
639 58 : string_printf(str, "%s Constant [ %s %s ] { %s }\n",
640 : indent, type, name, Z_STRVAL_P(value));
641 :
642 58 : if (use_copy) {
643 54 : zval_dtor(value);
644 : }
645 58 : }
646 : /* }}} */
647 :
648 : /* {{{ _get_recv_opcode */
649 : static zend_op* _get_recv_op(zend_op_array *op_array, zend_uint offset)
650 60 : {
651 60 : zend_op *op = op_array->opcodes;
652 60 : zend_op *end = op + op_array->last;
653 :
654 60 : ++offset;
655 233 : while (op < end) {
656 173 : if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
657 : && op->op1.u.constant.value.lval == (long)offset)
658 : {
659 60 : return op;
660 : }
661 113 : ++op;
662 : }
663 0 : return NULL;
664 : }
665 : /* }}} */
666 :
667 : /* {{{ _parameter_string */
668 : static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, char* indent TSRMLS_DC)
669 528 : {
670 528 : string_printf(str, "Parameter #%d [ ", offset);
671 528 : if (offset >= required) {
672 168 : string_printf(str, "<optional> ");
673 : } else {
674 360 : string_printf(str, "<required> ");
675 : }
676 528 : if (arg_info->class_name) {
677 5 : string_printf(str, "%s ", arg_info->class_name);
678 5 : if (arg_info->allow_null) {
679 1 : string_printf(str, "or NULL ");
680 : }
681 523 : } else if (arg_info->array_type_hint) {
682 10 : string_printf(str, "array ");
683 10 : if (arg_info->allow_null) {
684 1 : string_printf(str, "or NULL ");
685 : }
686 : }
687 528 : if (arg_info->pass_by_reference) {
688 13 : string_write(str, "&", sizeof("&")-1);
689 : }
690 528 : if (arg_info->name) {
691 528 : string_printf(str, "$%s", arg_info->name);
692 : } else {
693 0 : string_printf(str, "$param%d", offset);
694 : }
695 528 : if (fptr->type == ZEND_USER_FUNCTION && offset >= required) {
696 23 : zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset);
697 23 : if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2.op_type != IS_UNUSED) {
698 : zval *zv, zv_copy;
699 : int use_copy;
700 23 : string_write(str, " = ", sizeof(" = ")-1);
701 23 : ALLOC_ZVAL(zv);
702 23 : *zv = precv->op2.u.constant;
703 23 : zval_copy_ctor(zv);
704 23 : INIT_PZVAL(zv);
705 23 : zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
706 23 : if (Z_TYPE_P(zv) == IS_BOOL) {
707 2 : if (Z_LVAL_P(zv)) {
708 0 : string_write(str, "true", sizeof("true")-1);
709 : } else {
710 2 : string_write(str, "false", sizeof("false")-1);
711 : }
712 21 : } else if (Z_TYPE_P(zv) == IS_NULL) {
713 8 : string_write(str, "NULL", sizeof("NULL")-1);
714 13 : } else if (Z_TYPE_P(zv) == IS_STRING) {
715 9 : string_write(str, "'", sizeof("'")-1);
716 9 : string_write(str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 15));
717 9 : if (Z_STRLEN_P(zv) > 15) {
718 1 : string_write(str, "...", sizeof("...")-1);
719 : }
720 9 : string_write(str, "'", sizeof("'")-1);
721 : } else {
722 4 : zend_make_printable_zval(zv, &zv_copy, &use_copy);
723 4 : string_write(str, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy));
724 4 : if (use_copy) {
725 4 : zval_dtor(&zv_copy);
726 : }
727 : }
728 23 : zval_ptr_dtor(&zv);
729 : }
730 : }
731 528 : string_write(str, " ]", sizeof(" ]")-1);
732 528 : }
733 : /* }}} */
734 :
735 : /* {{{ _function_parameter_string */
736 : static void _function_parameter_string(string *str, zend_function *fptr, char* indent TSRMLS_DC)
737 715 : {
738 715 : struct _zend_arg_info *arg_info = fptr->common.arg_info;
739 715 : zend_uint i, required = fptr->common.required_num_args;
740 :
741 715 : if (!arg_info) {
742 58 : return;
743 : }
744 :
745 657 : string_printf(str, "\n");
746 657 : string_printf(str, "%s- Parameters [%d] {\n", indent, fptr->common.num_args);
747 1181 : for (i = 0; i < fptr->common.num_args; i++) {
748 524 : string_printf(str, "%s ", indent);
749 524 : _parameter_string(str, fptr, arg_info, i, required, indent TSRMLS_CC);
750 524 : string_write(str, "\n", sizeof("\n")-1);
751 524 : arg_info++;
752 : }
753 657 : string_printf(str, "%s}\n", indent);
754 : }
755 : /* }}} */
756 :
757 : /* {{{ _function_closure_string */
758 : static void _function_closure_string(string *str, zend_function *fptr, char* indent TSRMLS_DC)
759 0 : {
760 : zend_uint i, count;
761 : ulong num_index;
762 : char *key;
763 : uint key_len;
764 : HashTable *static_variables;
765 : HashPosition pos;
766 :
767 0 : if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) {
768 0 : return;
769 : }
770 :
771 0 : static_variables = fptr->op_array.static_variables;
772 0 : count = zend_hash_num_elements(static_variables);
773 :
774 0 : if (!count) {
775 0 : return;
776 : }
777 :
778 0 : string_printf(str, "\n");
779 0 : string_printf(str, "%s- Bound Variables [%d] {\n", indent, zend_hash_num_elements(static_variables));
780 0 : zend_hash_internal_pointer_reset_ex(static_variables, &pos);
781 0 : i = 0;
782 0 : while (i < count) {
783 0 : zend_hash_get_current_key_ex(static_variables, &key, &key_len, &num_index, 0, &pos);
784 0 : string_printf(str, "%s Variable #%d [ $%s ]\n", indent, i++, key);
785 0 : zend_hash_move_forward_ex(static_variables, &pos);
786 : }
787 0 : string_printf(str, "%s}\n", indent);
788 : }
789 : /* }}} */
790 :
791 : /* {{{ _function_string */
792 : static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char* indent TSRMLS_DC)
793 715 : {
794 : string param_indent;
795 : zend_function *overwrites;
796 : char *lc_name;
797 : unsigned int lc_name_len;
798 :
799 : /* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
800 : * What's "wrong" is that any whitespace before the doc comment start is
801 : * swallowed, leading to an unaligned comment.
802 : */
803 715 : if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
804 2 : string_printf(str, "%s%s\n", indent, fptr->op_array.doc_comment);
805 : }
806 :
807 715 : string_write(str, indent, strlen(indent));
808 715 : string_printf(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ "));
809 715 : string_printf(str, (fptr->type == ZEND_USER_FUNCTION) ? "<user" : "<internal");
810 715 : if (fptr->common.fn_flags & ZEND_ACC_DEPRECATED) {
811 0 : string_printf(str, ", deprecated");
812 : }
813 715 : if (fptr->type == ZEND_INTERNAL_FUNCTION && ((zend_internal_function*)fptr)->module) {
814 671 : string_printf(str, ":%s", ((zend_internal_function*)fptr)->module->name);
815 : }
816 :
817 715 : if (scope && fptr->common.scope) {
818 581 : if (fptr->common.scope != scope) {
819 185 : string_printf(str, ", inherits %s", fptr->common.scope->name);
820 396 : } else if (fptr->common.scope->parent) {
821 60 : lc_name_len = strlen(fptr->common.function_name);
822 60 : lc_name = zend_str_tolower_dup(fptr->common.function_name, lc_name_len);
823 60 : if (zend_hash_find(&fptr->common.scope->parent->function_table, lc_name, lc_name_len + 1, (void**) &overwrites) == SUCCESS) {
824 13 : if (fptr->common.scope != overwrites->common.scope) {
825 13 : string_printf(str, ", overwrites %s", overwrites->common.scope->name);
826 : }
827 : }
828 60 : efree(lc_name);
829 : }
830 : }
831 715 : if (fptr->common.prototype && fptr->common.prototype->common.scope) {
832 10 : string_printf(str, ", prototype %s", fptr->common.prototype->common.scope->name);
833 : }
834 715 : if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
835 21 : string_printf(str, ", ctor");
836 : }
837 715 : if (fptr->common.fn_flags & ZEND_ACC_DTOR) {
838 2 : string_printf(str, ", dtor");
839 : }
840 715 : string_printf(str, "> ");
841 :
842 715 : if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
843 9 : string_printf(str, "abstract ");
844 : }
845 715 : if (fptr->common.fn_flags & ZEND_ACC_FINAL) {
846 33 : string_printf(str, "final ");
847 : }
848 715 : if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
849 23 : string_printf(str, "static ");
850 : }
851 :
852 715 : if (fptr->common.scope) {
853 : /* These are mutually exclusive */
854 581 : switch (fptr->common.fn_flags & ZEND_ACC_PPP_MASK) {
855 : case ZEND_ACC_PUBLIC:
856 557 : string_printf(str, "public ");
857 557 : break;
858 : case ZEND_ACC_PRIVATE:
859 19 : string_printf(str, "private ");
860 19 : break;
861 : case ZEND_ACC_PROTECTED:
862 5 : string_printf(str, "protected ");
863 5 : break;
864 : default:
865 0 : string_printf(str, "<visibility error> ");
866 : break;
867 : }
868 581 : string_printf(str, "method ");
869 : } else {
870 134 : string_printf(str, "function ");
871 : }
872 :
873 715 : if (fptr->op_array.return_reference) {
874 0 : string_printf(str, "&");
875 : }
876 715 : string_printf(str, "%s ] {\n", fptr->common.function_name);
877 : /* The information where a function is declared is only available for user classes */
878 715 : if (fptr->type == ZEND_USER_FUNCTION) {
879 44 : string_printf(str, "%s @@ %s %d - %d\n", indent,
880 : fptr->op_array.filename,
881 : fptr->op_array.line_start,
882 : fptr->op_array.line_end);
883 : }
884 715 : string_init(¶m_indent);
885 715 : string_printf(¶m_indent, "%s ", indent);
886 715 : if (fptr->common.fn_flags & ZEND_ACC_CLOSURE) {
887 0 : _function_closure_string(str, fptr, param_indent.string TSRMLS_CC);
888 : }
889 715 : _function_parameter_string(str, fptr, param_indent.string TSRMLS_CC);
890 715 : string_free(¶m_indent);
891 715 : string_printf(str, "%s}\n", indent);
892 715 : }
893 : /* }}} */
894 :
895 : /* {{{ _property_string */
896 : static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent TSRMLS_DC)
897 65 : {
898 : char *class_name;
899 :
900 65 : string_printf(str, "%sProperty [ ", indent);
901 65 : if (!prop) {
902 5 : string_printf(str, "<dynamic> public $%s", prop_name);
903 : } else {
904 60 : if (!(prop->flags & ZEND_ACC_STATIC)) {
905 54 : if (prop->flags & ZEND_ACC_IMPLICIT_PUBLIC) {
906 0 : string_write(str, "<implicit> ", sizeof("<implicit> ") - 1);
907 : } else {
908 54 : string_write(str, "<default> ", sizeof("<default> ") - 1);
909 : }
910 : }
911 :
912 : /* These are mutually exclusive */
913 60 : switch (prop->flags & ZEND_ACC_PPP_MASK) {
914 : case ZEND_ACC_PUBLIC:
915 34 : string_printf(str, "public ");
916 34 : break;
917 : case ZEND_ACC_PRIVATE:
918 9 : string_printf(str, "private ");
919 9 : break;
920 : case ZEND_ACC_PROTECTED:
921 17 : string_printf(str, "protected ");
922 : break;
923 : }
924 60 : if(prop->flags & ZEND_ACC_STATIC) {
925 6 : string_printf(str, "static ");
926 : }
927 :
928 60 : zend_unmangle_property_name(prop->name, prop->name_length, &class_name, &prop_name);
929 60 : string_printf(str, "$%s", prop_name);
930 : }
931 :
932 65 : string_printf(str, " ]\n");
933 65 : }
934 : /* }}} */
935 :
936 : static int _extension_ini_string(zend_ini_entry *ini_entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
937 675 : {
938 675 : string *str = va_arg(args, string *);
939 675 : char *indent = va_arg(args, char *);
940 675 : int number = va_arg(args, int);
941 675 : char *comma = "";
942 :
943 675 : if (number == ini_entry->module_number) {
944 2 : string_printf(str, " %sEntry [ %s <", indent, ini_entry->name);
945 2 : if (ini_entry->modifiable == ZEND_INI_ALL) {
946 2 : string_printf(str, "ALL");
947 : } else {
948 0 : if (ini_entry->modifiable & ZEND_INI_USER) {
949 0 : string_printf(str, "USER");
950 0 : comma = ",";
951 : }
952 0 : if (ini_entry->modifiable & ZEND_INI_PERDIR) {
953 0 : string_printf(str, "%sPERDIR", comma);
954 0 : comma = ",";
955 : }
956 0 : if (ini_entry->modifiable & ZEND_INI_SYSTEM) {
957 0 : string_printf(str, "%sSYSTEM", comma);
958 : }
959 : }
960 :
961 2 : string_printf(str, "> ]\n");
962 2 : string_printf(str, " %s Current = '%s'\n", indent, ini_entry->value ? ini_entry->value : "");
963 2 : if (ini_entry->modified) {
964 0 : string_printf(str, " %s Default = '%s'\n", indent, ini_entry->orig_value ? ini_entry->orig_value : "");
965 : }
966 2 : string_printf(str, " %s}\n", indent);
967 : }
968 675 : return ZEND_HASH_APPLY_KEEP;
969 : }
970 :
971 : static int _extension_class_string(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
972 471 : {
973 471 : string *str = va_arg(args, string *);
974 471 : char *indent = va_arg(args, char *);
975 471 : struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
976 471 : int *num_classes = va_arg(args, int*);
977 :
978 471 : if ((*pce)->module && !strcasecmp((*pce)->module->name, module->name)) {
979 22 : string_printf(str, "\n");
980 22 : _class_string(str, *pce, NULL, indent TSRMLS_CC);
981 22 : (*num_classes)++;
982 : }
983 471 : return ZEND_HASH_APPLY_KEEP;
984 : }
985 :
986 : static int _extension_const_string(zend_constant *constant TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
987 6273 : {
988 6273 : string *str = va_arg(args, string *);
989 6273 : char *indent = va_arg(args, char *);
990 6273 : struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
991 6273 : int *num_classes = va_arg(args, int*);
992 :
993 6273 : if (constant->module_number == module->module_number) {
994 14 : _const_string(str, constant->name, &constant->value, indent TSRMLS_CC);
995 14 : (*num_classes)++;
996 : }
997 6273 : return ZEND_HASH_APPLY_KEEP;
998 : }
999 :
1000 : /* {{{ _extension_string */
1001 : static void _extension_string(string *str, zend_module_entry *module, char *indent TSRMLS_DC)
1002 3 : {
1003 3 : string_printf(str, "%sExtension [ ", indent);
1004 3 : if (module->type == MODULE_PERSISTENT) {
1005 3 : string_printf(str, "<persistent>");
1006 : }
1007 3 : if (module->type == MODULE_TEMPORARY) {
1008 0 : string_printf(str, "<temporary>" );
1009 : }
1010 3 : string_printf(str, " extension #%d %s version %s ] {\n",
1011 : module->module_number, module->name,
1012 : (module->version == NO_VERSION_YET) ? "<no_version>" : module->version);
1013 :
1014 3 : if (module->deps) {
1015 0 : const zend_module_dep* dep = module->deps;
1016 :
1017 0 : string_printf(str, "\n - Dependencies {\n");
1018 :
1019 0 : while(dep->name) {
1020 0 : string_printf(str, "%s Dependency [ %s (", indent, dep->name);
1021 :
1022 0 : switch(dep->type) {
1023 : case MODULE_DEP_REQUIRED:
1024 0 : string_write(str, "Required", sizeof("Required") - 1);
1025 0 : break;
1026 : case MODULE_DEP_CONFLICTS:
1027 0 : string_write(str, "Conflicts", sizeof("Conflicts") - 1);
1028 0 : break;
1029 : case MODULE_DEP_OPTIONAL:
1030 0 : string_write(str, "Optional", sizeof("Optional") - 1);
1031 0 : break;
1032 : default:
1033 0 : string_write(str, "Error", sizeof("Error") - 1); /* shouldn't happen */
1034 : break;
1035 : }
1036 :
1037 0 : if (dep->rel) {
1038 0 : string_printf(str, " %s", dep->rel);
1039 : }
1040 0 : if (dep->version) {
1041 0 : string_printf(str, " %s", dep->version);
1042 : }
1043 0 : string_write(str, ") ]\n", sizeof(") ]\n") - 1);
1044 0 : dep++;
1045 : }
1046 0 : string_printf(str, "%s }\n", indent);
1047 : }
1048 :
1049 : {
1050 : string str_ini;
1051 3 : string_init(&str_ini);
1052 3 : zend_hash_apply_with_arguments(EG(ini_directives) TSRMLS_CC, (apply_func_args_t) _extension_ini_string, 3, &str_ini, indent, module->module_number);
1053 3 : if (str_ini.len > 1) {
1054 1 : string_printf(str, "\n - INI {\n");
1055 1 : string_append(str, &str_ini);
1056 1 : string_printf(str, "%s }\n", indent);
1057 : }
1058 3 : string_free(&str_ini);
1059 : }
1060 :
1061 : {
1062 : string str_constants;
1063 3 : int num_constants = 0;
1064 :
1065 3 : string_init(&str_constants);
1066 3 : zend_hash_apply_with_arguments(EG(zend_constants) TSRMLS_CC, (apply_func_args_t) _extension_const_string, 4, &str_constants, indent, module, &num_constants);
1067 3 : if (num_constants) {
1068 1 : string_printf(str, "\n - Constants [%d] {\n", num_constants);
1069 1 : string_append(str, &str_constants);
1070 1 : string_printf(str, "%s }\n", indent);
1071 : }
1072 3 : string_free(&str_constants);
1073 : }
1074 :
1075 3 : if (module->functions && module->functions->fname) {
1076 : zend_function *fptr;
1077 1 : const zend_function_entry *func = module->functions;
1078 :
1079 1 : string_printf(str, "\n - Functions {\n");
1080 :
1081 : /* Is there a better way of doing this? */
1082 11 : while (func->fname) {
1083 9 : if (zend_hash_find(EG(function_table), func->fname, strlen(func->fname) + 1, (void**) &fptr) == FAILURE) {
1084 0 : zend_error(E_WARNING, "Internal error: Cannot find extension function %s in global function table", func->fname);
1085 0 : func++;
1086 0 : continue;
1087 : }
1088 :
1089 9 : _function_string(str, fptr, NULL, " " TSRMLS_CC);
1090 9 : func++;
1091 : }
1092 1 : string_printf(str, "%s }\n", indent);
1093 : }
1094 :
1095 : {
1096 : string str_classes;
1097 : string sub_indent;
1098 3 : int num_classes = 0;
1099 :
1100 3 : string_init(&sub_indent);
1101 3 : string_printf(&sub_indent, "%s ", indent);
1102 3 : string_init(&str_classes);
1103 3 : zend_hash_apply_with_arguments(EG(class_table) TSRMLS_CC, (apply_func_args_t) _extension_class_string, 4, &str_classes, sub_indent.string, module, &num_classes);
1104 3 : if (num_classes) {
1105 2 : string_printf(str, "\n - Classes [%d] {", num_classes);
1106 2 : string_append(str, &str_classes);
1107 2 : string_printf(str, "%s }\n", indent);
1108 : }
1109 3 : string_free(&str_classes);
1110 3 : string_free(&sub_indent);
1111 : }
1112 :
1113 3 : string_printf(str, "%s}\n", indent);
1114 3 : }
1115 : /* }}} */
1116 :
1117 : /* {{{ _function_check_flag */
1118 : static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
1119 410 : {
1120 : reflection_object *intern;
1121 : zend_function *mptr;
1122 :
1123 410 : if (zend_parse_parameters_none() == FAILURE) {
1124 6 : return;
1125 : }
1126 404 : GET_REFLECTION_OBJECT_PTR(mptr);
1127 404 : RETURN_BOOL(mptr->common.fn_flags & mask);
1128 : }
1129 : /* }}} */
1130 :
1131 : /* {{{ zend_reflection_class_factory */
1132 : PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_DC)
1133 123 : {
1134 : reflection_object *intern;
1135 : zval *name;
1136 :
1137 123 : MAKE_STD_ZVAL(name);
1138 123 : ZVAL_STRINGL(name, ce->name, ce->name_length, 1);
1139 123 : reflection_instantiate(reflection_class_ptr, object TSRMLS_CC);
1140 123 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1141 123 : intern->ptr = ce;
1142 123 : intern->ref_type = REF_TYPE_OTHER;
1143 123 : intern->ce = ce;
1144 123 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1145 123 : }
1146 : /* }}} */
1147 :
1148 : /* {{{ reflection_extension_factory */
1149 : static void reflection_extension_factory(zval *object, const char *name_str TSRMLS_DC)
1150 2 : {
1151 : reflection_object *intern;
1152 : zval *name;
1153 2 : int name_len = strlen(name_str);
1154 : char *lcname;
1155 : struct _zend_module_entry *module;
1156 : ALLOCA_FLAG(use_heap)
1157 :
1158 2 : lcname = do_alloca(name_len + 1, use_heap);
1159 2 : zend_str_tolower_copy(lcname, name_str, name_len);
1160 2 : if (zend_hash_find(&module_registry, lcname, name_len + 1, (void **)&module) == FAILURE) {
1161 0 : free_alloca(lcname, use_heap);
1162 0 : return;
1163 : }
1164 2 : free_alloca(lcname, use_heap);
1165 :
1166 2 : reflection_instantiate(reflection_extension_ptr, object TSRMLS_CC);
1167 2 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1168 2 : MAKE_STD_ZVAL(name);
1169 2 : ZVAL_STRINGL(name, module->name, name_len, 1);
1170 2 : intern->ptr = module;
1171 2 : intern->ref_type = REF_TYPE_OTHER;
1172 2 : intern->ce = NULL;
1173 2 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1174 : }
1175 : /* }}} */
1176 :
1177 : /* {{{ reflection_parameter_factory */
1178 : static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, zval *object TSRMLS_DC)
1179 71 : {
1180 : reflection_object *intern;
1181 : parameter_reference *reference;
1182 : zval *name;
1183 :
1184 71 : if (closure_object) {
1185 0 : Z_ADDREF_P(closure_object);
1186 : }
1187 71 : MAKE_STD_ZVAL(name);
1188 71 : if (arg_info->name) {
1189 71 : ZVAL_STRINGL(name, arg_info->name, arg_info->name_len, 1);
1190 : } else {
1191 0 : ZVAL_NULL(name);
1192 : }
1193 71 : reflection_instantiate(reflection_parameter_ptr, object TSRMLS_CC);
1194 71 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1195 71 : reference = (parameter_reference*) emalloc(sizeof(parameter_reference));
1196 71 : reference->arg_info = arg_info;
1197 71 : reference->offset = offset;
1198 71 : reference->required = required;
1199 71 : reference->fptr = fptr;
1200 71 : intern->ptr = reference;
1201 71 : intern->ref_type = REF_TYPE_PARAMETER;
1202 71 : intern->ce = fptr->common.scope;
1203 71 : intern->obj = closure_object;
1204 71 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1205 71 : }
1206 : /* }}} */
1207 :
1208 : /* {{{ reflection_function_factory */
1209 : static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object TSRMLS_DC)
1210 521 : {
1211 : reflection_object *intern;
1212 : zval *name;
1213 :
1214 521 : if (closure_object) {
1215 0 : Z_ADDREF_P(closure_object);
1216 : }
1217 521 : MAKE_STD_ZVAL(name);
1218 521 : ZVAL_STRING(name, function->common.function_name, 1);
1219 :
1220 521 : reflection_instantiate(reflection_function_ptr, object TSRMLS_CC);
1221 521 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1222 521 : intern->ptr = function;
1223 521 : intern->ref_type = REF_TYPE_FUNCTION;
1224 521 : intern->ce = NULL;
1225 521 : intern->obj = closure_object;
1226 521 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1227 521 : }
1228 : /* }}} */
1229 :
1230 : /* {{{ reflection_method_factory */
1231 : static void reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object TSRMLS_DC)
1232 282 : {
1233 : reflection_object *intern;
1234 : zval *name;
1235 : zval *classname;
1236 :
1237 282 : if (closure_object) {
1238 0 : Z_ADDREF_P(closure_object);
1239 : }
1240 282 : MAKE_STD_ZVAL(name);
1241 282 : MAKE_STD_ZVAL(classname);
1242 282 : ZVAL_STRING(name, method->common.function_name, 1);
1243 282 : ZVAL_STRINGL(classname, method->common.scope->name, method->common.scope->name_length, 1);
1244 282 : reflection_instantiate(reflection_method_ptr, object TSRMLS_CC);
1245 282 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1246 282 : intern->ptr = method;
1247 282 : intern->ref_type = REF_TYPE_FUNCTION;
1248 282 : intern->ce = ce;
1249 282 : intern->obj = closure_object;
1250 282 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1251 282 : zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
1252 282 : }
1253 : /* }}} */
1254 :
1255 : /* {{{ reflection_property_factory */
1256 : static void reflection_property_factory(zend_class_entry *ce, zend_property_info *prop, zval *object TSRMLS_DC)
1257 146 : {
1258 : reflection_object *intern;
1259 : zval *name;
1260 : zval *classname;
1261 : property_reference *reference;
1262 : char *class_name, *prop_name;
1263 :
1264 146 : zend_unmangle_property_name(prop->name, prop->name_length, &class_name, &prop_name);
1265 :
1266 146 : if (!(prop->flags & ZEND_ACC_PRIVATE)) {
1267 : /* we have to search the class hierarchy for this (implicit) public or protected property */
1268 116 : zend_class_entry *tmp_ce = ce, *store_ce = ce;
1269 116 : zend_property_info *tmp_info = NULL;
1270 :
1271 244 : while (tmp_ce && zend_hash_find(&tmp_ce->properties_info, prop_name, strlen(prop_name) + 1, (void **) &tmp_info) != SUCCESS) {
1272 12 : ce = tmp_ce;
1273 12 : tmp_ce = tmp_ce->parent;
1274 : }
1275 :
1276 222 : if (tmp_info && !(tmp_info->flags & ZEND_ACC_SHADOW)) { /* found something and it's not a parent's private */
1277 106 : prop = tmp_info;
1278 : } else { /* not found, use initial value */
1279 10 : ce = store_ce;
1280 : }
1281 : }
1282 :
1283 146 : MAKE_STD_ZVAL(name);
1284 146 : MAKE_STD_ZVAL(classname);
1285 146 : ZVAL_STRING(name, prop_name, 1);
1286 146 : ZVAL_STRINGL(classname, prop->ce->name, prop->ce->name_length, 1);
1287 :
1288 146 : reflection_instantiate(reflection_property_ptr, object TSRMLS_CC);
1289 146 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1290 146 : reference = (property_reference*) emalloc(sizeof(property_reference));
1291 146 : reference->ce = ce;
1292 146 : reference->prop = *prop;
1293 146 : intern->ptr = reference;
1294 146 : intern->ref_type = REF_TYPE_PROPERTY;
1295 146 : intern->ce = ce;
1296 146 : intern->ignore_visibility = 0;
1297 146 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1298 146 : zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
1299 146 : }
1300 : /* }}} */
1301 :
1302 : /* {{{ _reflection_export */
1303 : static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc)
1304 44 : {
1305 : zval *reflector_ptr;
1306 44 : zval output, *output_ptr = &output;
1307 : zval *argument_ptr, *argument2_ptr;
1308 : zval *retval_ptr, **params[2];
1309 : int result;
1310 44 : int return_output = 0;
1311 : zend_fcall_info fci;
1312 : zend_fcall_info_cache fcc;
1313 : zval fname;
1314 :
1315 44 : if (ctor_argc == 1) {
1316 14 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &argument_ptr, &return_output) == FAILURE) {
1317 0 : return;
1318 : }
1319 : } else {
1320 30 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|b", &argument_ptr, &argument2_ptr, &return_output) == FAILURE) {
1321 4 : return;
1322 : }
1323 : }
1324 :
1325 40 : INIT_PZVAL(&output);
1326 :
1327 : /* Create object */
1328 40 : MAKE_STD_ZVAL(reflector_ptr);
1329 40 : if (object_and_properties_init(reflector_ptr, ce_ptr, NULL) == FAILURE) {
1330 0 : _DO_THROW("Could not create reflector");
1331 : }
1332 :
1333 : /* Call __construct() */
1334 40 : params[0] = &argument_ptr;
1335 40 : params[1] = &argument2_ptr;
1336 :
1337 40 : fci.size = sizeof(fci);
1338 40 : fci.function_table = NULL;
1339 40 : fci.function_name = NULL;
1340 40 : fci.symbol_table = NULL;
1341 40 : fci.object_ptr = reflector_ptr;
1342 40 : fci.retval_ptr_ptr = &retval_ptr;
1343 40 : fci.param_count = ctor_argc;
1344 40 : fci.params = params;
1345 40 : fci.no_separation = 1;
1346 :
1347 40 : fcc.initialized = 1;
1348 40 : fcc.function_handler = ce_ptr->constructor;
1349 40 : fcc.calling_scope = ce_ptr;
1350 40 : fcc.called_scope = Z_OBJCE_P(reflector_ptr);
1351 40 : fcc.object_ptr = reflector_ptr;
1352 :
1353 40 : result = zend_call_function(&fci, &fcc TSRMLS_CC);
1354 :
1355 40 : if (retval_ptr) {
1356 33 : zval_ptr_dtor(&retval_ptr);
1357 : }
1358 :
1359 40 : if (EG(exception)) {
1360 7 : zval_ptr_dtor(&reflector_ptr);
1361 7 : return;
1362 : }
1363 33 : if (result == FAILURE) {
1364 0 : zval_ptr_dtor(&reflector_ptr);
1365 0 : _DO_THROW("Could not create reflector");
1366 : }
1367 :
1368 : /* Call static reflection::export */
1369 33 : ZVAL_BOOL(&output, return_output);
1370 33 : params[0] = &reflector_ptr;
1371 33 : params[1] = &output_ptr;
1372 :
1373 33 : ZVAL_STRINGL(&fname, "reflection::export", sizeof("reflection::export") - 1, 0);
1374 33 : fci.function_table = &reflection_ptr->function_table;
1375 33 : fci.function_name = &fname;
1376 33 : fci.object_ptr = NULL;
1377 33 : fci.retval_ptr_ptr = &retval_ptr;
1378 33 : fci.param_count = 2;
1379 33 : fci.params = params;
1380 33 : fci.no_separation = 1;
1381 :
1382 33 : result = zend_call_function(&fci, NULL TSRMLS_CC);
1383 :
1384 33 : if (result == FAILURE && EG(exception) == NULL) {
1385 0 : zval_ptr_dtor(&reflector_ptr);
1386 0 : zval_ptr_dtor(&retval_ptr);
1387 0 : _DO_THROW("Could not execute reflection::export()");
1388 : }
1389 :
1390 33 : if (return_output) {
1391 13 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1392 : } else {
1393 20 : zval_ptr_dtor(&retval_ptr);
1394 : }
1395 :
1396 : /* Destruct reflector which is no longer needed */
1397 33 : zval_ptr_dtor(&reflector_ptr);
1398 : }
1399 : /* }}} */
1400 :
1401 : /* {{{ Preventing __clone from being called */
1402 : ZEND_METHOD(reflection, __clone)
1403 0 : {
1404 : /* Should never be executable */
1405 0 : _DO_THROW("Cannot clone object using __clone()");
1406 : }
1407 : /* }}} */
1408 :
1409 : /* {{{ proto public static mixed Reflection::export(Reflector r [, bool return])
1410 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
1411 : ZEND_METHOD(reflection, export)
1412 165 : {
1413 : zval *object, fname, *retval_ptr;
1414 : int result;
1415 165 : zend_bool return_output = 0;
1416 :
1417 165 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &object, reflector_ptr, &return_output) == FAILURE) {
1418 2 : return;
1419 : }
1420 :
1421 : /* Invoke the __toString() method */
1422 163 : ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1, 1);
1423 163 : result= call_user_function_ex(NULL, &object, &fname, &retval_ptr, 0, NULL, 0, NULL TSRMLS_CC);
1424 163 : zval_dtor(&fname);
1425 :
1426 163 : if (result == FAILURE) {
1427 0 : _DO_THROW("Invocation of method __toString() failed");
1428 : /* Returns from this function */
1429 : }
1430 :
1431 163 : if (!retval_ptr) {
1432 0 : zend_error(E_WARNING, "%s::__toString() did not return anything", Z_OBJCE_P(object)->name);
1433 0 : RETURN_FALSE;
1434 : }
1435 :
1436 163 : if (return_output) {
1437 13 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1438 : } else {
1439 : /* No need for _r variant, return of __toString should always be a string */
1440 150 : zend_print_zval(retval_ptr, 0);
1441 150 : zend_printf("\n");
1442 150 : zval_ptr_dtor(&retval_ptr);
1443 : }
1444 : }
1445 : /* }}} */
1446 :
1447 : /* {{{ proto public static array Reflection::getModifierNames(int modifiers)
1448 : Returns an array of modifier names */
1449 : ZEND_METHOD(reflection, getModifierNames)
1450 17 : {
1451 : long modifiers;
1452 :
1453 17 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &modifiers) == FAILURE) {
1454 0 : return;
1455 : }
1456 :
1457 17 : array_init(return_value);
1458 :
1459 17 : if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1460 3 : add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1, 1);
1461 : }
1462 17 : if (modifiers & (ZEND_ACC_FINAL | ZEND_ACC_FINAL_CLASS)) {
1463 3 : add_next_index_stringl(return_value, "final", sizeof("final")-1, 1);
1464 : }
1465 17 : if (modifiers & ZEND_ACC_IMPLICIT_PUBLIC) {
1466 1 : add_next_index_stringl(return_value, "public", sizeof("public")-1, 1);
1467 : }
1468 :
1469 : /* These are mutually exclusive */
1470 17 : switch (modifiers & ZEND_ACC_PPP_MASK) {
1471 : case ZEND_ACC_PUBLIC:
1472 7 : add_next_index_stringl(return_value, "public", sizeof("public")-1, 1);
1473 7 : break;
1474 : case ZEND_ACC_PRIVATE:
1475 2 : add_next_index_stringl(return_value, "private", sizeof("private")-1, 1);
1476 2 : break;
1477 : case ZEND_ACC_PROTECTED:
1478 4 : add_next_index_stringl(return_value, "protected", sizeof("protected")-1, 1);
1479 : break;
1480 : }
1481 :
1482 17 : if (modifiers & ZEND_ACC_STATIC) {
1483 3 : add_next_index_stringl(return_value, "static", sizeof("static")-1, 1);
1484 : }
1485 : }
1486 : /* }}} */
1487 :
1488 : /* {{{ proto public static mixed ReflectionFunction::export(string name [, bool return])
1489 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
1490 : ZEND_METHOD(reflection_function, export)
1491 2 : {
1492 2 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_function_ptr, 1);
1493 2 : }
1494 : /* }}} */
1495 :
1496 : /* {{{ proto public void ReflectionFunction::__construct(string name)
1497 : Constructor. Throws an Exception in case the given function does not exist */
1498 : ZEND_METHOD(reflection_function, __construct)
1499 165 : {
1500 : zval *name;
1501 : zval *object;
1502 165 : zval *closure = NULL;
1503 : char *lcname;
1504 : reflection_object *intern;
1505 : zend_function *fptr;
1506 : char *name_str;
1507 : int name_len;
1508 :
1509 165 : object = getThis();
1510 165 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1511 165 : if (intern == NULL) {
1512 0 : return;
1513 : }
1514 :
1515 165 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &closure, zend_ce_closure) == SUCCESS) {
1516 1 : fptr = (zend_function*)zend_get_closure_method_def(closure TSRMLS_CC);
1517 1 : Z_ADDREF_P(closure);
1518 164 : } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == SUCCESS) {
1519 : char *nsname;
1520 :
1521 161 : lcname = zend_str_tolower_dup(name_str, name_len);
1522 :
1523 : /* Ignore leading "\" */
1524 161 : nsname = lcname;
1525 161 : if (lcname[0] == '\\') {
1526 1 : nsname = &lcname[1];
1527 1 : name_len--;
1528 : }
1529 :
1530 161 : if (zend_hash_find(EG(function_table), nsname, name_len + 1, (void **)&fptr) == FAILURE) {
1531 3 : efree(lcname);
1532 3 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
1533 : "Function %s() does not exist", name_str);
1534 3 : return;
1535 : }
1536 158 : efree(lcname);
1537 : } else {
1538 3 : return;
1539 : }
1540 :
1541 159 : MAKE_STD_ZVAL(name);
1542 159 : ZVAL_STRING(name, fptr->common.function_name, 1);
1543 159 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
1544 159 : intern->ptr = fptr;
1545 159 : intern->ref_type = REF_TYPE_FUNCTION;
1546 159 : intern->obj = closure;
1547 159 : intern->ce = NULL;
1548 : }
1549 : /* }}} */
1550 :
1551 : /* {{{ proto public string ReflectionFunction::__toString()
1552 : Returns a string representation */
1553 : ZEND_METHOD(reflection_function, __toString)
1554 125 : {
1555 : reflection_object *intern;
1556 : zend_function *fptr;
1557 : string str;
1558 :
1559 125 : if (zend_parse_parameters_none() == FAILURE) {
1560 0 : return;
1561 : }
1562 125 : GET_REFLECTION_OBJECT_PTR(fptr);
1563 125 : string_init(&str);
1564 125 : _function_string(&str, fptr, intern->ce, "" TSRMLS_CC);
1565 125 : RETURN_STRINGL(str.string, str.len - 1, 0);
1566 : }
1567 : /* }}} */
1568 :
1569 : /* {{{ proto public string ReflectionFunction::getName()
1570 : Returns this function's name */
1571 : ZEND_METHOD(reflection_function, getName)
1572 191 : {
1573 191 : if (zend_parse_parameters_none() == FAILURE) {
1574 1 : return;
1575 : }
1576 190 : _default_get_entry(getThis(), "name", sizeof("name"), return_value TSRMLS_CC);
1577 : }
1578 : /* }}} */
1579 :
1580 : /* {{{ proto public bool ReflectionFunction::isClosure()
1581 : Returns whether this is a closure */
1582 : ZEND_METHOD(reflection_function, isClosure)
1583 1 : {
1584 : reflection_object *intern;
1585 : zend_function *fptr;
1586 :
1587 1 : if (zend_parse_parameters_none() == FAILURE) {
1588 0 : return;
1589 : }
1590 1 : GET_REFLECTION_OBJECT_PTR(fptr);
1591 1 : RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_CLOSURE);
1592 : }
1593 : /* }}} */
1594 :
1595 : /* {{{ proto public bool ReflectionFunction::isInternal()
1596 : Returns whether this is an internal function */
1597 : ZEND_METHOD(reflection_function, isInternal)
1598 73 : {
1599 : reflection_object *intern;
1600 : zend_function *fptr;
1601 :
1602 73 : if (zend_parse_parameters_none() == FAILURE) {
1603 1 : return;
1604 : }
1605 72 : GET_REFLECTION_OBJECT_PTR(fptr);
1606 72 : RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION);
1607 : }
1608 : /* }}} */
1609 :
1610 : /* {{{ proto public bool ReflectionFunction::isUserDefined()
1611 : Returns whether this is an user-defined function */
1612 : ZEND_METHOD(reflection_function, isUserDefined)
1613 73 : {
1614 : reflection_object *intern;
1615 : zend_function *fptr;
1616 :
1617 73 : if (zend_parse_parameters_none() == FAILURE) {
1618 1 : return;
1619 : }
1620 72 : GET_REFLECTION_OBJECT_PTR(fptr);
1621 72 : RETURN_BOOL(fptr->type == ZEND_USER_FUNCTION);
1622 : }
1623 : /* }}} */
1624 :
1625 : /* {{{ proto public bool ReflectionFunction::isDisabled()
1626 : Returns whether this function has been disabled or not */
1627 : ZEND_METHOD(reflection_function, isDisabled)
1628 1 : {
1629 : reflection_object *intern;
1630 : zend_function *fptr;
1631 :
1632 1 : METHOD_NOTSTATIC(reflection_function_ptr);
1633 1 : GET_REFLECTION_OBJECT_PTR(fptr);
1634 1 : RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.handler == zif_display_disabled_function);
1635 : }
1636 : /* }}} */
1637 :
1638 : /* {{{ proto public string ReflectionFunction::getFileName()
1639 : Returns the filename of the file this function was declared in */
1640 : ZEND_METHOD(reflection_function, getFileName)
1641 15 : {
1642 : reflection_object *intern;
1643 : zend_function *fptr;
1644 :
1645 15 : if (zend_parse_parameters_none() == FAILURE) {
1646 1 : return;
1647 : }
1648 14 : GET_REFLECTION_OBJECT_PTR(fptr);
1649 14 : if (fptr->type == ZEND_USER_FUNCTION) {
1650 12 : RETURN_STRING(fptr->op_array.filename, 1);
1651 : }
1652 2 : RETURN_FALSE;
1653 : }
1654 : /* }}} */
1655 :
1656 : /* {{{ proto public int ReflectionFunction::getStartLine()
1657 : Returns the line this function's declaration starts at */
1658 : ZEND_METHOD(reflection_function, getStartLine)
1659 14 : {
1660 : reflection_object *intern;
1661 : zend_function *fptr;
1662 :
1663 14 : if (zend_parse_parameters_none() == FAILURE) {
1664 1 : return;
1665 : }
1666 13 : GET_REFLECTION_OBJECT_PTR(fptr);
1667 13 : if (fptr->type == ZEND_USER_FUNCTION) {
1668 11 : RETURN_LONG(fptr->op_array.line_start);
1669 : }
1670 2 : RETURN_FALSE;
1671 : }
1672 : /* }}} */
1673 :
1674 : /* {{{ proto public int ReflectionFunction::getEndLine()
1675 : Returns the line this function's declaration ends at */
1676 : ZEND_METHOD(reflection_function, getEndLine)
1677 14 : {
1678 : reflection_object *intern;
1679 : zend_function *fptr;
1680 :
1681 14 : if (zend_parse_parameters_none() == FAILURE) {
1682 1 : return;
1683 : }
1684 13 : GET_REFLECTION_OBJECT_PTR(fptr);
1685 13 : if (fptr->type == ZEND_USER_FUNCTION) {
1686 11 : RETURN_LONG(fptr->op_array.line_end);
1687 : }
1688 2 : RETURN_FALSE;
1689 : }
1690 : /* }}} */
1691 :
1692 : /* {{{ proto public string ReflectionFunction::getDocComment()
1693 : Returns the doc comment for this function */
1694 : ZEND_METHOD(reflection_function, getDocComment)
1695 20 : {
1696 : reflection_object *intern;
1697 : zend_function *fptr;
1698 :
1699 20 : if (zend_parse_parameters_none() == FAILURE) {
1700 2 : return;
1701 : }
1702 18 : GET_REFLECTION_OBJECT_PTR(fptr);
1703 18 : if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
1704 12 : RETURN_STRINGL(fptr->op_array.doc_comment, fptr->op_array.doc_comment_len, 1);
1705 : }
1706 6 : RETURN_FALSE;
1707 : }
1708 : /* }}} */
1709 :
1710 : /* {{{ proto public array ReflectionFunction::getStaticVariables()
1711 : Returns an associative array containing this function's static variables and their values */
1712 : ZEND_METHOD(reflection_function, getStaticVariables)
1713 70 : {
1714 : zval *tmp_copy;
1715 : reflection_object *intern;
1716 : zend_function *fptr;
1717 :
1718 70 : if (zend_parse_parameters_none() == FAILURE) {
1719 1 : return;
1720 : }
1721 69 : GET_REFLECTION_OBJECT_PTR(fptr);
1722 :
1723 : /* Return an empty array in case no static variables exist */
1724 69 : array_init(return_value);
1725 69 : if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
1726 6 : zend_hash_apply_with_argument(fptr->op_array.static_variables, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC);
1727 6 : zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_copy, sizeof(zval *));
1728 : }
1729 : }
1730 : /* }}} */
1731 :
1732 : /* {{{ proto public mixed ReflectionFunction::invoke([mixed* args])
1733 : Invokes the function */
1734 : ZEND_METHOD(reflection_function, invoke)
1735 4 : {
1736 : zval *retval_ptr;
1737 4 : zval ***params = NULL;
1738 4 : int result, num_args = 0;
1739 : zend_fcall_info fci;
1740 : zend_fcall_info_cache fcc;
1741 : reflection_object *intern;
1742 : zend_function *fptr;
1743 :
1744 4 : METHOD_NOTSTATIC(reflection_function_ptr);
1745 4 : GET_REFLECTION_OBJECT_PTR(fptr);
1746 :
1747 4 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", ¶ms, &num_args) == FAILURE) {
1748 0 : return;
1749 : }
1750 :
1751 4 : fci.size = sizeof(fci);
1752 4 : fci.function_table = NULL;
1753 4 : fci.function_name = NULL;
1754 4 : fci.symbol_table = NULL;
1755 4 : fci.object_ptr = NULL;
1756 4 : fci.retval_ptr_ptr = &retval_ptr;
1757 4 : fci.param_count = num_args;
1758 4 : fci.params = params;
1759 4 : fci.no_separation = 1;
1760 :
1761 4 : fcc.initialized = 1;
1762 4 : fcc.function_handler = fptr;
1763 4 : fcc.calling_scope = EG(scope);
1764 4 : fcc.called_scope = NULL;
1765 4 : fcc.object_ptr = NULL;
1766 :
1767 4 : result = zend_call_function(&fci, &fcc TSRMLS_CC);
1768 :
1769 4 : if (num_args) {
1770 3 : efree(params);
1771 : }
1772 :
1773 4 : if (result == FAILURE) {
1774 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
1775 : "Invocation of function %s() failed", fptr->common.function_name);
1776 0 : return;
1777 : }
1778 :
1779 4 : if (retval_ptr) {
1780 4 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1781 : }
1782 : }
1783 : /* }}} */
1784 :
1785 : static int _zval_array_to_c_array(zval **arg, zval ****params TSRMLS_DC) /* {{{ */
1786 28 : {
1787 28 : *(*params)++ = arg;
1788 28 : return ZEND_HASH_APPLY_KEEP;
1789 : } /* }}} */
1790 :
1791 : /* {{{ proto public mixed ReflectionFunction::invokeArgs(array args)
1792 : Invokes the function and pass its arguments as array. */
1793 : ZEND_METHOD(reflection_function, invokeArgs)
1794 3 : {
1795 : zval *retval_ptr;
1796 : zval ***params;
1797 : int result;
1798 : int argc;
1799 : zend_fcall_info fci;
1800 : zend_fcall_info_cache fcc;
1801 : reflection_object *intern;
1802 : zend_function *fptr;
1803 : zval *param_array;
1804 :
1805 3 : METHOD_NOTSTATIC(reflection_function_ptr);
1806 3 : GET_REFLECTION_OBJECT_PTR(fptr);
1807 :
1808 3 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", ¶m_array) == FAILURE) {
1809 0 : return;
1810 : }
1811 :
1812 3 : argc = zend_hash_num_elements(Z_ARRVAL_P(param_array));
1813 :
1814 3 : params = safe_emalloc(sizeof(zval **), argc, 0);
1815 3 : zend_hash_apply_with_argument(Z_ARRVAL_P(param_array), (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC);
1816 3 : params -= argc;
1817 :
1818 3 : fci.size = sizeof(fci);
1819 3 : fci.function_table = NULL;
1820 3 : fci.function_name = NULL;
1821 3 : fci.symbol_table = NULL;
1822 3 : fci.object_ptr = NULL;
1823 3 : fci.retval_ptr_ptr = &retval_ptr;
1824 3 : fci.param_count = argc;
1825 3 : fci.params = params;
1826 3 : fci.no_separation = 1;
1827 :
1828 3 : fcc.initialized = 1;
1829 3 : fcc.function_handler = fptr;
1830 3 : fcc.calling_scope = EG(scope);
1831 3 : fcc.called_scope = NULL;
1832 3 : fcc.object_ptr = NULL;
1833 :
1834 3 : result = zend_call_function(&fci, &fcc TSRMLS_CC);
1835 :
1836 3 : efree(params);
1837 :
1838 3 : if (result == FAILURE) {
1839 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
1840 : "Invocation of function %s() failed", fptr->common.function_name);
1841 0 : return;
1842 : }
1843 :
1844 3 : if (retval_ptr) {
1845 3 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1846 : }
1847 : }
1848 : /* }}} */
1849 :
1850 : /* {{{ proto public bool ReflectionFunction::returnsReference()
1851 : Gets whether this function returns a reference */
1852 : ZEND_METHOD(reflection_function, returnsReference)
1853 63 : {
1854 : reflection_object *intern;
1855 : zend_function *fptr;
1856 :
1857 63 : METHOD_NOTSTATIC(reflection_function_abstract_ptr);
1858 63 : GET_REFLECTION_OBJECT_PTR(fptr);
1859 :
1860 63 : RETURN_BOOL(fptr->op_array.return_reference);
1861 : }
1862 : /* }}} */
1863 :
1864 : /* {{{ proto public bool ReflectionFunction::getNumberOfParameters()
1865 : Gets the number of required parameters */
1866 : ZEND_METHOD(reflection_function, getNumberOfParameters)
1867 66 : {
1868 : reflection_object *intern;
1869 : zend_function *fptr;
1870 :
1871 66 : METHOD_NOTSTATIC(reflection_function_abstract_ptr);
1872 66 : GET_REFLECTION_OBJECT_PTR(fptr);
1873 :
1874 66 : RETURN_LONG(fptr->common.num_args);
1875 : }
1876 : /* }}} */
1877 :
1878 : /* {{{ proto public bool ReflectionFunction::getNumberOfRequiredParameters()
1879 : Gets the number of required parameters */
1880 : ZEND_METHOD(reflection_function, getNumberOfRequiredParameters)
1881 67 : {
1882 : reflection_object *intern;
1883 : zend_function *fptr;
1884 :
1885 67 : METHOD_NOTSTATIC(reflection_function_abstract_ptr);
1886 67 : GET_REFLECTION_OBJECT_PTR(fptr);
1887 :
1888 67 : RETURN_LONG(fptr->common.required_num_args);
1889 : }
1890 : /* }}} */
1891 :
1892 : /* {{{ proto public ReflectionParameter[] ReflectionFunction::getParameters()
1893 : Returns an array of parameter objects for this function */
1894 : ZEND_METHOD(reflection_function, getParameters)
1895 86 : {
1896 : reflection_object *intern;
1897 : zend_function *fptr;
1898 : zend_uint i;
1899 : struct _zend_arg_info *arg_info;
1900 :
1901 86 : METHOD_NOTSTATIC(reflection_function_abstract_ptr);
1902 86 : GET_REFLECTION_OBJECT_PTR(fptr);
1903 :
1904 86 : arg_info= fptr->common.arg_info;
1905 :
1906 86 : array_init(return_value);
1907 157 : for (i = 0; i < fptr->common.num_args; i++) {
1908 : zval *parameter;
1909 :
1910 71 : ALLOC_ZVAL(parameter);
1911 71 : reflection_parameter_factory(_copy_function(fptr TSRMLS_CC), intern->obj, arg_info, i, fptr->common.required_num_args, parameter TSRMLS_CC);
1912 71 : add_next_index_zval(return_value, parameter);
1913 :
1914 71 : arg_info++;
1915 : }
1916 : }
1917 : /* }}} */
1918 :
1919 : /* {{{ proto public ReflectionExtension|NULL ReflectionFunction::getExtension()
1920 : Returns NULL or the extension the function belongs to */
1921 : ZEND_METHOD(reflection_function, getExtension)
1922 2 : {
1923 : reflection_object *intern;
1924 : zend_function *fptr;
1925 : zend_internal_function *internal;
1926 :
1927 2 : METHOD_NOTSTATIC(reflection_function_abstract_ptr);
1928 2 : GET_REFLECTION_OBJECT_PTR(fptr);
1929 :
1930 2 : if (fptr->type != ZEND_INTERNAL_FUNCTION) {
1931 1 : RETURN_NULL();
1932 : }
1933 :
1934 1 : internal = (zend_internal_function *)fptr;
1935 1 : if (internal->module) {
1936 1 : reflection_extension_factory(return_value, internal->module->name TSRMLS_CC);
1937 : } else {
1938 0 : RETURN_NULL();
1939 : }
1940 : }
1941 : /* }}} */
1942 :
1943 : /* {{{ proto public string|false ReflectionFunction::getExtensionName()
1944 : Returns false or the name of the extension the function belongs to */
1945 : ZEND_METHOD(reflection_function, getExtensionName)
1946 3 : {
1947 : reflection_object *intern;
1948 : zend_function *fptr;
1949 : zend_internal_function *internal;
1950 :
1951 3 : METHOD_NOTSTATIC(reflection_function_abstract_ptr);
1952 3 : GET_REFLECTION_OBJECT_PTR(fptr);
1953 :
1954 3 : if (fptr->type != ZEND_INTERNAL_FUNCTION) {
1955 1 : RETURN_FALSE;
1956 : }
1957 :
1958 2 : internal = (zend_internal_function *)fptr;
1959 2 : if (internal->module) {
1960 2 : RETURN_STRING(internal->module->name, 1);
1961 : } else {
1962 0 : RETURN_FALSE;
1963 : }
1964 : }
1965 : /* }}} */
1966 :
1967 : /* {{{ proto public static mixed ReflectionParameter::export(mixed function, mixed parameter [, bool return]) throws ReflectionException
1968 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
1969 : ZEND_METHOD(reflection_parameter, export)
1970 8 : {
1971 8 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_parameter_ptr, 2);
1972 8 : }
1973 : /* }}} */
1974 :
1975 : /* {{{ proto public void ReflectionParameter::__construct(mixed function, mixed parameter)
1976 : Constructor. Throws an Exception in case the given method does not exist */
1977 : ZEND_METHOD(reflection_parameter, __construct)
1978 25 : {
1979 : parameter_reference *ref;
1980 : zval *reference, **parameter;
1981 : zval *object;
1982 : zval *name;
1983 : reflection_object *intern;
1984 : zend_function *fptr;
1985 : struct _zend_arg_info *arg_info;
1986 : int position;
1987 25 : zend_class_entry *ce = NULL;
1988 25 : zend_bool is_closure = 0;
1989 :
1990 25 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zZ", &reference, ¶meter) == FAILURE) {
1991 0 : return;
1992 : }
1993 :
1994 25 : object = getThis();
1995 25 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
1996 25 : if (intern == NULL) {
1997 0 : return;
1998 : }
1999 :
2000 : /* First, find the function */
2001 25 : switch (Z_TYPE_P(reference)) {
2002 : case IS_STRING: {
2003 : unsigned int lcname_len;
2004 : char *lcname;
2005 :
2006 4 : lcname_len = Z_STRLEN_P(reference);
2007 4 : lcname = zend_str_tolower_dup(Z_STRVAL_P(reference), lcname_len);
2008 4 : if (zend_hash_find(EG(function_table), lcname, lcname_len + 1, (void**) &fptr) == FAILURE) {
2009 0 : efree(lcname);
2010 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2011 : "Function %s() does not exist", Z_STRVAL_P(reference));
2012 0 : return;
2013 : }
2014 4 : efree(lcname);
2015 : }
2016 4 : ce = fptr->common.scope;
2017 4 : break;
2018 :
2019 : case IS_ARRAY: {
2020 : zval **classref;
2021 : zval **method;
2022 : zend_class_entry **pce;
2023 : unsigned int lcname_len;
2024 : char *lcname;
2025 :
2026 14 : if ((zend_hash_index_find(Z_ARRVAL_P(reference), 0, (void **) &classref) == FAILURE)
2027 : || (zend_hash_index_find(Z_ARRVAL_P(reference), 1, (void **) &method) == FAILURE))
2028 : {
2029 0 : _DO_THROW("Expected array($object, $method) or array($classname, $method)");
2030 : /* returns out of this function */
2031 : }
2032 :
2033 14 : if (Z_TYPE_PP(classref) == IS_OBJECT) {
2034 8 : ce = Z_OBJCE_PP(classref);
2035 : } else {
2036 6 : convert_to_string_ex(classref);
2037 6 : if (zend_lookup_class(Z_STRVAL_PP(classref), Z_STRLEN_PP(classref), &pce TSRMLS_CC) == FAILURE) {
2038 1 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2039 : "Class %s does not exist", Z_STRVAL_PP(classref));
2040 1 : return;
2041 : }
2042 5 : ce = *pce;
2043 : }
2044 :
2045 13 : convert_to_string_ex(method);
2046 13 : lcname_len = Z_STRLEN_PP(method);
2047 13 : lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), lcname_len);
2048 13 : if (ce == zend_ce_closure && Z_TYPE_PP(classref) == IS_OBJECT
2049 : && (lcname_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
2050 : && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
2051 : && (fptr = zend_get_closure_invoke_method(*classref TSRMLS_CC)) != NULL)
2052 : {
2053 : /* nothign to do. don't set is_closure since is the invoke handler,
2054 : not the closure itself */
2055 8 : } else if (zend_hash_find(&ce->function_table, lcname, lcname_len + 1, (void **) &fptr) == FAILURE) {
2056 2 : efree(lcname);
2057 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2058 : "Method %s::%s() does not exist", ce->name, Z_STRVAL_PP(method));
2059 2 : return;
2060 : }
2061 11 : efree(lcname);
2062 : }
2063 11 : break;
2064 :
2065 : case IS_OBJECT: {
2066 6 : ce = Z_OBJCE_P(reference);
2067 :
2068 6 : if (instanceof_function(ce, zend_ce_closure TSRMLS_CC)) {
2069 5 : fptr = (zend_function *)zend_get_closure_method_def(reference TSRMLS_CC);
2070 5 : Z_ADDREF_P(reference);
2071 5 : is_closure = 1;
2072 1 : } else if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME), (void **)&fptr) == FAILURE) {
2073 1 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2074 : "Method %s::%s() does not exist", ce->name, ZEND_INVOKE_FUNC_NAME);
2075 1 : return;
2076 : }
2077 : }
2078 5 : break;
2079 :
2080 : default:
2081 1 : _DO_THROW("The parameter class is expected to be either a string, an array(class, method) or a callable object");
2082 : /* returns out of this function */
2083 : }
2084 :
2085 : /* Now, search for the parameter */
2086 20 : arg_info = fptr->common.arg_info;
2087 20 : if (Z_TYPE_PP(parameter) == IS_LONG) {
2088 9 : position= Z_LVAL_PP(parameter);
2089 9 : if (position < 0 || (zend_uint)position >= fptr->common.num_args) {
2090 1 : if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
2091 0 : if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
2092 0 : efree(fptr->common.function_name);
2093 : }
2094 0 : efree(fptr);
2095 : }
2096 1 : if (is_closure) {
2097 1 : zval_ptr_dtor(&reference);
2098 : }
2099 1 : _DO_THROW("The parameter specified by its offset could not be found");
2100 : /* returns out of this function */
2101 : }
2102 : } else {
2103 : zend_uint i;
2104 :
2105 11 : position= -1;
2106 11 : convert_to_string_ex(parameter);
2107 19 : for (i = 0; i < fptr->common.num_args; i++) {
2108 17 : if (arg_info[i].name && strcmp(arg_info[i].name, Z_STRVAL_PP(parameter)) == 0) {
2109 9 : position= i;
2110 9 : break;
2111 : }
2112 : }
2113 11 : if (position == -1) {
2114 2 : if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) {
2115 0 : if (fptr->type != ZEND_OVERLOADED_FUNCTION) {
2116 0 : efree(fptr->common.function_name);
2117 : }
2118 0 : efree(fptr);
2119 : }
2120 2 : if (is_closure) {
2121 0 : zval_ptr_dtor(&reference);
2122 : }
2123 2 : _DO_THROW("The parameter specified by its name could not be found");
2124 : /* returns out of this function */
2125 : }
2126 : }
2127 :
2128 17 : MAKE_STD_ZVAL(name);
2129 17 : if (arg_info[position].name) {
2130 17 : ZVAL_STRINGL(name, arg_info[position].name, arg_info[position].name_len, 1);
2131 : } else {
2132 0 : ZVAL_NULL(name);
2133 : }
2134 17 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
2135 :
2136 17 : ref = (parameter_reference*) emalloc(sizeof(parameter_reference));
2137 17 : ref->arg_info = &arg_info[position];
2138 17 : ref->offset = (zend_uint)position;
2139 17 : ref->required = fptr->common.required_num_args;
2140 17 : ref->fptr = fptr;
2141 : /* TODO: copy fptr */
2142 17 : intern->ptr = ref;
2143 17 : intern->ref_type = REF_TYPE_PARAMETER;
2144 17 : intern->ce = ce;
2145 17 : if (reference && is_closure) {
2146 4 : intern->obj = reference;
2147 : }
2148 : }
2149 : /* }}} */
2150 :
2151 : /* {{{ proto public string ReflectionParameter::__toString()
2152 : Returns a string representation */
2153 : ZEND_METHOD(reflection_parameter, __toString)
2154 4 : {
2155 : reflection_object *intern;
2156 : parameter_reference *param;
2157 : string str;
2158 :
2159 4 : if (zend_parse_parameters_none() == FAILURE) {
2160 0 : return;
2161 : }
2162 4 : GET_REFLECTION_OBJECT_PTR(param);
2163 4 : string_init(&str);
2164 4 : _parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "" TSRMLS_CC);
2165 4 : RETURN_STRINGL(str.string, str.len - 1, 0);
2166 : }
2167 : /* }}} */
2168 :
2169 : /* {{{ proto public string ReflectionParameter::getName()
2170 : Returns this parameters's name */
2171 : ZEND_METHOD(reflection_parameter, getName)
2172 34 : {
2173 34 : if (zend_parse_parameters_none() == FAILURE) {
2174 0 : return;
2175 : }
2176 34 : _default_get_entry(getThis(), "name", sizeof("name"), return_value TSRMLS_CC);
2177 : }
2178 : /* }}} */
2179 :
2180 : /* {{{ proto public ReflectionFunction ReflectionParameter::getDeclaringFunction()
2181 : Returns the ReflectionFunction for the function of this parameter */
2182 : ZEND_METHOD(reflection_parameter, getDeclaringFunction)
2183 4 : {
2184 : reflection_object *intern;
2185 : parameter_reference *param;
2186 :
2187 4 : if (zend_parse_parameters_none() == FAILURE) {
2188 0 : return;
2189 : }
2190 4 : GET_REFLECTION_OBJECT_PTR(param);
2191 :
2192 4 : if (!param->fptr->common.scope) {
2193 2 : reflection_function_factory(_copy_function(param->fptr TSRMLS_CC), intern->obj, return_value TSRMLS_CC);
2194 : } else {
2195 2 : reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr TSRMLS_CC), intern->obj, return_value TSRMLS_CC);
2196 : }
2197 : }
2198 : /* }}} */
2199 :
2200 : /* {{{ proto public ReflectionClass|NULL ReflectionParameter::getDeclaringClass()
2201 : Returns in which class this parameter is defined (not the typehint of the parameter) */
2202 : ZEND_METHOD(reflection_parameter, getDeclaringClass)
2203 14 : {
2204 : reflection_object *intern;
2205 : parameter_reference *param;
2206 :
2207 14 : if (zend_parse_parameters_none() == FAILURE) {
2208 0 : return;
2209 : }
2210 14 : GET_REFLECTION_OBJECT_PTR(param);
2211 :
2212 14 : if (param->fptr->common.scope) {
2213 7 : zend_reflection_class_factory(param->fptr->common.scope, return_value TSRMLS_CC);
2214 : }
2215 : }
2216 : /* }}} */
2217 :
2218 : /* {{{ proto public ReflectionClass|NULL ReflectionParameter::getClass()
2219 : Returns this parameters's class hint or NULL if there is none */
2220 : ZEND_METHOD(reflection_parameter, getClass)
2221 17 : {
2222 : reflection_object *intern;
2223 : parameter_reference *param;
2224 : zend_class_entry **pce, *ce;
2225 :
2226 17 : if (zend_parse_parameters_none() == FAILURE) {
2227 0 : return;
2228 : }
2229 17 : GET_REFLECTION_OBJECT_PTR(param);
2230 :
2231 17 : if (param->arg_info->class_name) {
2232 : /* Class name is stored as a string, we might also get "self" or "parent"
2233 : * - For "self", simply use the function scope. If scope is NULL then
2234 : * the function is global and thus self does not make any sense
2235 : *
2236 : * - For "parent", use the function scope's parent. If scope is NULL then
2237 : * the function is global and thus parent does not make any sense.
2238 : * If the parent is NULL then the class does not extend anything and
2239 : * thus parent does not make any sense, either.
2240 : *
2241 : * TODO: Think about moving these checks to the compiler or some sort of
2242 : * lint-mode.
2243 : */
2244 9 : if (0 == strncmp(param->arg_info->class_name, "self", sizeof("self")- 1)) {
2245 1 : ce = param->fptr->common.scope;
2246 1 : if (!ce) {
2247 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2248 : "Parameter uses 'self' as type hint but function is not a class member!");
2249 0 : return;
2250 : }
2251 1 : pce= &ce;
2252 8 : } else if (0 == strncmp(param->arg_info->class_name, "parent", sizeof("parent")- 1)) {
2253 0 : ce = param->fptr->common.scope;
2254 0 : if (!ce) {
2255 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2256 : "Parameter uses 'parent' as type hint but function is not a class member!");
2257 0 : return;
2258 : }
2259 0 : if (!ce->parent) {
2260 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2261 : "Parameter uses 'parent' as type hint although class does not have a parent!");
2262 0 : return;
2263 : }
2264 0 : pce= &ce->parent;
2265 8 : } else if (zend_lookup_class(param->arg_info->class_name, param->arg_info->class_name_len, &pce TSRMLS_CC) == FAILURE) {
2266 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2267 : "Class %s does not exist", param->arg_info->class_name);
2268 2 : return;
2269 : }
2270 7 : zend_reflection_class_factory(*pce, return_value TSRMLS_CC);
2271 : }
2272 : }
2273 : /* }}} */
2274 :
2275 : /* {{{ proto public bool ReflectionParameter::isArray()
2276 : Returns whether parameter MUST be an array */
2277 : ZEND_METHOD(reflection_parameter, isArray)
2278 14 : {
2279 : reflection_object *intern;
2280 : parameter_reference *param;
2281 :
2282 14 : if (zend_parse_parameters_none() == FAILURE) {
2283 0 : return;
2284 : }
2285 14 : GET_REFLECTION_OBJECT_PTR(param);
2286 :
2287 14 : RETVAL_BOOL(param->arg_info->array_type_hint);
2288 : }
2289 : /* }}} */
2290 :
2291 : /* {{{ proto public bool ReflectionParameter::allowsNull()
2292 : Returns whether NULL is allowed as this parameters's value */
2293 : ZEND_METHOD(reflection_parameter, allowsNull)
2294 14 : {
2295 : reflection_object *intern;
2296 : parameter_reference *param;
2297 :
2298 14 : if (zend_parse_parameters_none() == FAILURE) {
2299 0 : return;
2300 : }
2301 14 : GET_REFLECTION_OBJECT_PTR(param);
2302 :
2303 14 : RETVAL_BOOL(param->arg_info->allow_null);
2304 : }
2305 : /* }}} */
2306 :
2307 : /* {{{ proto public bool ReflectionParameter::isPassedByReference()
2308 : Returns whether this parameters is passed to by reference */
2309 : ZEND_METHOD(reflection_parameter, isPassedByReference)
2310 18 : {
2311 : reflection_object *intern;
2312 : parameter_reference *param;
2313 :
2314 18 : if (zend_parse_parameters_none() == FAILURE) {
2315 0 : return;
2316 : }
2317 18 : GET_REFLECTION_OBJECT_PTR(param);
2318 :
2319 18 : RETVAL_BOOL(param->arg_info->pass_by_reference);
2320 : }
2321 : /* }}} */
2322 :
2323 : /* {{{ proto public bool ReflectionParameter::getPosition()
2324 : Returns whether this parameter is an optional parameter */
2325 : ZEND_METHOD(reflection_parameter, getPosition)
2326 2 : {
2327 : reflection_object *intern;
2328 : parameter_reference *param;
2329 :
2330 2 : if (zend_parse_parameters_none() == FAILURE) {
2331 0 : return;
2332 : }
2333 2 : GET_REFLECTION_OBJECT_PTR(param);
2334 :
2335 2 : RETVAL_LONG(param->offset);
2336 : }
2337 : /* }}} */
2338 :
2339 : /* {{{ proto public bool ReflectionParameter::isOptional()
2340 : Returns whether this parameter is an optional parameter */
2341 : ZEND_METHOD(reflection_parameter, isOptional)
2342 50 : {
2343 : reflection_object *intern;
2344 : parameter_reference *param;
2345 :
2346 50 : if (zend_parse_parameters_none() == FAILURE) {
2347 0 : return;
2348 : }
2349 50 : GET_REFLECTION_OBJECT_PTR(param);
2350 :
2351 50 : RETVAL_BOOL(param->offset >= param->required);
2352 : }
2353 : /* }}} */
2354 :
2355 : /* {{{ proto public bool ReflectionParameter::isDefaultValueAvailable()
2356 : Returns whether the default value of this parameter is available */
2357 : ZEND_METHOD(reflection_parameter, isDefaultValueAvailable)
2358 32 : {
2359 : reflection_object *intern;
2360 : parameter_reference *param;
2361 : zend_op *precv;
2362 :
2363 32 : if (zend_parse_parameters_none() == FAILURE) {
2364 0 : return;
2365 : }
2366 32 : GET_REFLECTION_OBJECT_PTR(param);
2367 :
2368 32 : if (param->fptr->type != ZEND_USER_FUNCTION)
2369 : {
2370 0 : RETURN_FALSE;
2371 : }
2372 32 : if (param->offset < param->required) {
2373 12 : RETURN_FALSE;
2374 : }
2375 20 : precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
2376 20 : if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) {
2377 0 : RETURN_FALSE;
2378 : }
2379 20 : RETURN_TRUE;
2380 : }
2381 : /* }}} */
2382 :
2383 : /* {{{ proto public bool ReflectionParameter::getDefaultValue()
2384 : Returns the default value of this parameter or throws an exception */
2385 : ZEND_METHOD(reflection_parameter, getDefaultValue)
2386 17 : {
2387 : reflection_object *intern;
2388 : parameter_reference *param;
2389 : zend_op *precv;
2390 :
2391 17 : if (zend_parse_parameters_none() == FAILURE) {
2392 0 : return;
2393 : }
2394 17 : GET_REFLECTION_OBJECT_PTR(param);
2395 :
2396 17 : if (param->fptr->type != ZEND_USER_FUNCTION)
2397 : {
2398 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions");
2399 0 : return;
2400 : }
2401 17 : if (param->offset < param->required) {
2402 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional");
2403 0 : return;
2404 : }
2405 17 : precv = _get_recv_op((zend_op_array*)param->fptr, param->offset);
2406 17 : if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) {
2407 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error");
2408 0 : return;
2409 : }
2410 :
2411 17 : *return_value = precv->op2.u.constant;
2412 17 : INIT_PZVAL(return_value);
2413 17 : if (Z_TYPE_P(return_value) != IS_CONSTANT) {
2414 9 : zval_copy_ctor(return_value);
2415 : }
2416 17 : zval_update_constant_ex(&return_value, (void*)0, param->fptr->common.scope TSRMLS_CC);
2417 : }
2418 : /* }}} */
2419 :
2420 : /* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
2421 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
2422 : ZEND_METHOD(reflection_method, export)
2423 8 : {
2424 8 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_method_ptr, 2);
2425 8 : }
2426 : /* }}} */
2427 :
2428 : /* {{{ proto public void ReflectionMethod::__construct(mixed class_or_method [, string name])
2429 : Constructor. Throws an Exception in case the given method does not exist */
2430 : ZEND_METHOD(reflection_method, __construct)
2431 136 : {
2432 : zval *name, *classname;
2433 : zval *object, *orig_obj;
2434 : reflection_object *intern;
2435 : char *lcname;
2436 : zend_class_entry **pce;
2437 : zend_class_entry *ce;
2438 : zend_function *mptr;
2439 : char *name_str, *tmp;
2440 : int name_len, tmp_len;
2441 : zval ztmp;
2442 :
2443 136 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) {
2444 48 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) {
2445 4 : return;
2446 : }
2447 44 : if ((tmp = strstr(name_str, "::")) == NULL) {
2448 5 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invalid method name %s", name_str);
2449 5 : return;
2450 : }
2451 39 : classname = &ztmp;
2452 39 : tmp_len = tmp - name_str;
2453 39 : ZVAL_STRINGL(classname, name_str, tmp_len, 1);
2454 39 : name_len = name_len - (tmp_len + 2);
2455 39 : name_str = tmp + 2;
2456 39 : orig_obj = NULL;
2457 88 : } else if (Z_TYPE_P(classname) == IS_OBJECT) {
2458 5 : orig_obj = classname;
2459 : } else {
2460 83 : orig_obj = NULL;
2461 : }
2462 :
2463 127 : object = getThis();
2464 127 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
2465 127 : if (intern == NULL) {
2466 0 : return;
2467 : }
2468 :
2469 : /* Find the class entry */
2470 127 : switch (Z_TYPE_P(classname)) {
2471 : case IS_STRING:
2472 120 : if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) {
2473 8 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2474 : "Class %s does not exist", Z_STRVAL_P(classname));
2475 8 : if (classname == &ztmp) {
2476 6 : zval_dtor(&ztmp);
2477 : }
2478 8 : return;
2479 : }
2480 112 : ce = *pce;
2481 112 : break;
2482 :
2483 : case IS_OBJECT:
2484 5 : ce = Z_OBJCE_P(classname);
2485 5 : break;
2486 :
2487 : default:
2488 2 : if (classname == &ztmp) {
2489 0 : zval_dtor(&ztmp);
2490 : }
2491 2 : _DO_THROW("The parameter class is expected to be either a string or an object");
2492 : /* returns out of this function */
2493 : }
2494 :
2495 117 : if (classname == &ztmp) {
2496 33 : zval_dtor(&ztmp);
2497 : }
2498 :
2499 117 : lcname = zend_str_tolower_dup(name_str, name_len);
2500 :
2501 117 : if (ce == zend_ce_closure && orig_obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
2502 : && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
2503 : && (mptr = zend_get_closure_invoke_method(orig_obj TSRMLS_CC)) != NULL)
2504 : {
2505 : /* do nothing, mptr already set */
2506 115 : } else if (zend_hash_find(&ce->function_table, lcname, name_len + 1, (void **) &mptr) == FAILURE) {
2507 3 : efree(lcname);
2508 3 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2509 : "Method %s::%s() does not exist", ce->name, name_str);
2510 3 : return;
2511 : }
2512 114 : efree(lcname);
2513 :
2514 114 : MAKE_STD_ZVAL(classname);
2515 114 : ZVAL_STRINGL(classname, mptr->common.scope->name, mptr->common.scope->name_length, 1);
2516 :
2517 114 : zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
2518 :
2519 114 : MAKE_STD_ZVAL(name);
2520 114 : ZVAL_STRING(name, mptr->common.function_name, 1);
2521 114 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
2522 114 : intern->ptr = mptr;
2523 114 : intern->ref_type = REF_TYPE_FUNCTION;
2524 114 : intern->ce = ce;
2525 : }
2526 : /* }}} */
2527 :
2528 : /* {{{ proto public string ReflectionMethod::__toString()
2529 : Returns a string representation */
2530 : ZEND_METHOD(reflection_method, __toString)
2531 18 : {
2532 : reflection_object *intern;
2533 : zend_function *mptr;
2534 : string str;
2535 :
2536 18 : if (zend_parse_parameters_none() == FAILURE) {
2537 0 : return;
2538 : }
2539 18 : GET_REFLECTION_OBJECT_PTR(mptr);
2540 18 : string_init(&str);
2541 18 : _function_string(&str, mptr, intern->ce, "" TSRMLS_CC);
2542 18 : RETURN_STRINGL(str.string, str.len - 1, 0);
2543 : }
2544 : /* }}} */
2545 :
2546 : /* {{{ proto public mixed ReflectionMethod::invoke(mixed object, mixed* args)
2547 : Invokes the method. */
2548 : ZEND_METHOD(reflection_method, invoke)
2549 30 : {
2550 : zval *retval_ptr;
2551 30 : zval ***params = NULL;
2552 : zval *object_ptr;
2553 : reflection_object *intern;
2554 : zend_function *mptr;
2555 30 : int result, num_args = 0;
2556 : zend_fcall_info fci;
2557 : zend_fcall_info_cache fcc;
2558 : zend_class_entry *obj_ce;
2559 :
2560 30 : METHOD_NOTSTATIC(reflection_method_ptr);
2561 :
2562 30 : GET_REFLECTION_OBJECT_PTR(mptr);
2563 :
2564 30 : if ((!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)
2565 : || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT))
2566 : && intern->ignore_visibility == 0)
2567 : {
2568 6 : if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
2569 1 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2570 : "Trying to invoke abstract method %s::%s()",
2571 : mptr->common.scope->name, mptr->common.function_name);
2572 : } else {
2573 5 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2574 : "Trying to invoke %s method %s::%s() from scope %s",
2575 : mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private",
2576 : mptr->common.scope->name, mptr->common.function_name,
2577 : Z_OBJCE_P(getThis())->name);
2578 : }
2579 6 : return;
2580 : }
2581 :
2582 24 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", ¶ms, &num_args) == FAILURE) {
2583 1 : return;
2584 : }
2585 :
2586 : /* In case this is a static method, we should'nt pass an object_ptr
2587 : * (which is used as calling context aka $this). We can thus ignore the
2588 : * first parameter.
2589 : *
2590 : * Else, we verify that the given object is an instance of the class.
2591 : */
2592 23 : if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
2593 7 : object_ptr = NULL;
2594 7 : obj_ce = mptr->common.scope;
2595 : } else {
2596 16 : if (Z_TYPE_PP(params[0]) != IS_OBJECT) {
2597 2 : efree(params);
2598 2 : _DO_THROW("Non-object passed to Invoke()");
2599 : /* Returns from this function */
2600 : }
2601 :
2602 14 : obj_ce = Z_OBJCE_PP(params[0]);
2603 :
2604 14 : if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) {
2605 2 : if (params) {
2606 2 : efree(params);
2607 : }
2608 2 : _DO_THROW("Given object is not an instance of the class this method was declared in");
2609 : /* Returns from this function */
2610 : }
2611 :
2612 12 : object_ptr = *params[0];
2613 : }
2614 :
2615 19 : fci.size = sizeof(fci);
2616 19 : fci.function_table = NULL;
2617 19 : fci.function_name = NULL;
2618 19 : fci.symbol_table = NULL;
2619 19 : fci.object_ptr = object_ptr;
2620 19 : fci.retval_ptr_ptr = &retval_ptr;
2621 19 : fci.param_count = num_args - 1;
2622 19 : fci.params = params + 1;
2623 19 : fci.no_separation = 1;
2624 :
2625 19 : fcc.initialized = 1;
2626 19 : fcc.function_handler = mptr;
2627 19 : fcc.calling_scope = obj_ce;
2628 19 : fcc.called_scope = obj_ce;
2629 19 : fcc.object_ptr = object_ptr;
2630 :
2631 19 : result = zend_call_function(&fci, &fcc TSRMLS_CC);
2632 :
2633 19 : if (params) {
2634 19 : efree(params);
2635 : }
2636 :
2637 19 : if (result == FAILURE) {
2638 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2639 : "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name);
2640 0 : return;
2641 : }
2642 :
2643 19 : if (retval_ptr) {
2644 17 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
2645 : }
2646 : }
2647 : /* }}} */
2648 :
2649 : /* {{{ proto public mixed ReflectionMethod::invokeArgs(mixed object, array args)
2650 : Invokes the function and pass its arguments as array. */
2651 : ZEND_METHOD(reflection_method, invokeArgs)
2652 28 : {
2653 : zval *retval_ptr;
2654 : zval ***params;
2655 : zval *object;
2656 : reflection_object *intern;
2657 : zend_function *mptr;
2658 : int argc;
2659 : int result;
2660 : zend_fcall_info fci;
2661 : zend_fcall_info_cache fcc;
2662 : zend_class_entry *obj_ce;
2663 : zval *param_array;
2664 :
2665 28 : METHOD_NOTSTATIC(reflection_method_ptr);
2666 :
2667 28 : GET_REFLECTION_OBJECT_PTR(mptr);
2668 :
2669 28 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!a", &object, ¶m_array) == FAILURE) {
2670 7 : return;
2671 : }
2672 :
2673 21 : if ((!(mptr->common.fn_flags & ZEND_ACC_PUBLIC)
2674 : || (mptr->common.fn_flags & ZEND_ACC_ABSTRACT))
2675 : && intern->ignore_visibility == 0)
2676 : {
2677 6 : if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
2678 1 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2679 : "Trying to invoke abstract method %s::%s()",
2680 : mptr->common.scope->name, mptr->common.function_name);
2681 : } else {
2682 5 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2683 : "Trying to invoke %s method %s::%s() from scope %s",
2684 : mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private",
2685 : mptr->common.scope->name, mptr->common.function_name,
2686 : Z_OBJCE_P(getThis())->name);
2687 : }
2688 6 : return;
2689 : }
2690 :
2691 15 : argc = zend_hash_num_elements(Z_ARRVAL_P(param_array));
2692 :
2693 15 : params = safe_emalloc(sizeof(zval **), argc, 0);
2694 15 : zend_hash_apply_with_argument(Z_ARRVAL_P(param_array), (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC);
2695 15 : params -= argc;
2696 :
2697 : /* In case this is a static method, we should'nt pass an object_ptr
2698 : * (which is used as calling context aka $this). We can thus ignore the
2699 : * first parameter.
2700 : *
2701 : * Else, we verify that the given object is an instance of the class.
2702 : */
2703 15 : if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
2704 4 : object = NULL;
2705 4 : obj_ce = mptr->common.scope;
2706 : } else {
2707 11 : if (!object) {
2708 0 : efree(params);
2709 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2710 : "Trying to invoke non static method %s::%s() without an object",
2711 : mptr->common.scope->name, mptr->common.function_name);
2712 0 : return;
2713 : }
2714 :
2715 11 : obj_ce = Z_OBJCE_P(object);
2716 :
2717 11 : if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) {
2718 1 : efree(params);
2719 1 : _DO_THROW("Given object is not an instance of the class this method was declared in");
2720 : /* Returns from this function */
2721 : }
2722 : }
2723 :
2724 14 : fci.size = sizeof(fci);
2725 14 : fci.function_table = NULL;
2726 14 : fci.function_name = NULL;
2727 14 : fci.symbol_table = NULL;
2728 14 : fci.object_ptr = object;
2729 14 : fci.retval_ptr_ptr = &retval_ptr;
2730 14 : fci.param_count = argc;
2731 14 : fci.params = params;
2732 14 : fci.no_separation = 1;
2733 :
2734 14 : fcc.initialized = 1;
2735 14 : fcc.function_handler = mptr;
2736 14 : fcc.calling_scope = obj_ce;
2737 14 : fcc.called_scope = obj_ce;
2738 14 : fcc.object_ptr = object;
2739 :
2740 14 : result = zend_call_function(&fci, &fcc TSRMLS_CC);
2741 :
2742 14 : efree(params);
2743 :
2744 14 : if (result == FAILURE) {
2745 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2746 : "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name);
2747 0 : return;
2748 : }
2749 :
2750 14 : if (retval_ptr) {
2751 12 : COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
2752 : }
2753 : }
2754 : /* }}} */
2755 :
2756 : /* {{{ proto public bool ReflectionMethod::isFinal()
2757 : Returns whether this method is final */
2758 : ZEND_METHOD(reflection_method, isFinal)
2759 68 : {
2760 68 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
2761 68 : }
2762 : /* }}} */
2763 :
2764 : /* {{{ proto public bool ReflectionMethod::isAbstract()
2765 : Returns whether this method is abstract */
2766 : ZEND_METHOD(reflection_method, isAbstract)
2767 69 : {
2768 69 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ABSTRACT);
2769 69 : }
2770 : /* }}} */
2771 :
2772 : /* {{{ proto public bool ReflectionMethod::isPublic()
2773 : Returns whether this method is public */
2774 : ZEND_METHOD(reflection_method, isPublic)
2775 68 : {
2776 68 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
2777 68 : }
2778 : /* }}} */
2779 :
2780 : /* {{{ proto public bool ReflectionMethod::isPrivate()
2781 : Returns whether this method is private */
2782 : ZEND_METHOD(reflection_method, isPrivate)
2783 68 : {
2784 68 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
2785 68 : }
2786 : /* }}} */
2787 :
2788 : /* {{{ proto public bool ReflectionMethod::isProtected()
2789 : Returns whether this method is protected */
2790 : ZEND_METHOD(reflection_method, isProtected)
2791 68 : {
2792 68 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
2793 68 : }
2794 : /* }}} */
2795 :
2796 : /* {{{ proto public bool ReflectionMethod::isStatic()
2797 : Returns whether this method is static */
2798 : ZEND_METHOD(reflection_method, isStatic)
2799 68 : {
2800 68 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
2801 68 : }
2802 : /* }}} */
2803 :
2804 : /* {{{ proto public bool ReflectionFunction::isDeprecated()
2805 : Returns whether this function is deprecated */
2806 : ZEND_METHOD(reflection_function, isDeprecated)
2807 1 : {
2808 1 : _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_DEPRECATED);
2809 1 : }
2810 : /* }}} */
2811 :
2812 : /* {{{ proto public bool ReflectionFunction::inNamespace()
2813 : Returns whether this function is defined in namespace */
2814 : ZEND_METHOD(reflection_function, inNamespace)
2815 2 : {
2816 : zval **name;
2817 : char *colon;
2818 :
2819 2 : if (zend_parse_parameters_none() == FAILURE) {
2820 0 : return;
2821 : }
2822 2 : if (zend_hash_find(Z_OBJPROP_P(getThis()), "name", sizeof("name"), (void **) &name) == FAILURE) {
2823 0 : RETURN_FALSE;
2824 : }
2825 2 : if (Z_TYPE_PP(name) == IS_STRING
2826 : && (colon = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name)))
2827 : && colon > Z_STRVAL_PP(name))
2828 : {
2829 1 : RETURN_TRUE;
2830 : }
2831 1 : RETURN_FALSE;
2832 : }
2833 : /* }}} */
2834 :
2835 : /* {{{ proto public string ReflectionFunction::getNamespaceName()
2836 : Returns the name of namespace where this function is defined */
2837 : ZEND_METHOD(reflection_function, getNamespaceName)
2838 2 : {
2839 : zval **name;
2840 : char *backslash;
2841 :
2842 2 : if (zend_parse_parameters_none() == FAILURE) {
2843 0 : return;
2844 : }
2845 2 : if (zend_hash_find(Z_OBJPROP_P(getThis()), "name", sizeof("name"), (void **) &name) == FAILURE) {
2846 0 : RETURN_FALSE;
2847 : }
2848 2 : if (Z_TYPE_PP(name) == IS_STRING
2849 : && (backslash = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name)))
2850 : && backslash > Z_STRVAL_PP(name))
2851 : {
2852 1 : RETURN_STRINGL(Z_STRVAL_PP(name), backslash - Z_STRVAL_PP(name), 1);
2853 : }
2854 1 : RETURN_EMPTY_STRING();
2855 : }
2856 : /* }}} */
2857 :
2858 : /* {{{ proto public string ReflectionFunction::getShortName()
2859 : Returns the short name of the function (without namespace part) */
2860 : ZEND_METHOD(reflection_function, getShortName)
2861 2 : {
2862 : zval **name;
2863 : char *backslash;
2864 :
2865 2 : if (zend_parse_parameters_none() == FAILURE) {
2866 0 : return;
2867 : }
2868 2 : if (zend_hash_find(Z_OBJPROP_P(getThis()), "name", sizeof("name"), (void **) &name) == FAILURE) {
2869 0 : RETURN_FALSE;
2870 : }
2871 2 : if (Z_TYPE_PP(name) == IS_STRING
2872 : && (backslash = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name)))
2873 : && backslash > Z_STRVAL_PP(name))
2874 : {
2875 1 : RETURN_STRINGL(backslash + 1, Z_STRLEN_PP(name) - (backslash - Z_STRVAL_PP(name) + 1), 1);
2876 : }
2877 1 : RETURN_ZVAL(*name, 1, 0);
2878 : }
2879 : /* }}} */
2880 :
2881 : /* {{{ proto public bool ReflectionMethod::isConstructor()
2882 : Returns whether this method is the constructor */
2883 : ZEND_METHOD(reflection_method, isConstructor)
2884 84 : {
2885 : reflection_object *intern;
2886 : zend_function *mptr;
2887 :
2888 84 : if (zend_parse_parameters_none() == FAILURE) {
2889 1 : return;
2890 : }
2891 83 : GET_REFLECTION_OBJECT_PTR(mptr);
2892 : /* we need to check if the ctor is the ctor of the class level we we
2893 : * looking at since we might be looking at an inherited old style ctor
2894 : * defined in base class. */
2895 83 : RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_CTOR && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope);
2896 : }
2897 : /* }}} */
2898 :
2899 : /* {{{ proto public bool ReflectionMethod::isDestructor()
2900 : Returns whether this method is static */
2901 : ZEND_METHOD(reflection_method, isDestructor)
2902 68 : {
2903 : reflection_object *intern;
2904 : zend_function *mptr;
2905 :
2906 68 : if (zend_parse_parameters_none() == FAILURE) {
2907 1 : return;
2908 : }
2909 67 : GET_REFLECTION_OBJECT_PTR(mptr);
2910 67 : RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_DTOR);
2911 : }
2912 : /* }}} */
2913 :
2914 : /* {{{ proto public int ReflectionMethod::getModifiers()
2915 : Returns a bitfield of the access modifiers for this method */
2916 : ZEND_METHOD(reflection_method, getModifiers)
2917 111 : {
2918 : reflection_object *intern;
2919 : zend_function *mptr;
2920 :
2921 111 : if (zend_parse_parameters_none() == FAILURE) {
2922 2 : return;
2923 : }
2924 109 : GET_REFLECTION_OBJECT_PTR(mptr);
2925 :
2926 109 : RETURN_LONG(mptr->common.fn_flags);
2927 : }
2928 : /* }}} */
2929 :
2930 : /* {{{ proto public ReflectionClass ReflectionMethod::getDeclaringClass()
2931 : Get the declaring class */
2932 : ZEND_METHOD(reflection_method, getDeclaringClass)
2933 15 : {
2934 : reflection_object *intern;
2935 : zend_function *mptr;
2936 :
2937 15 : METHOD_NOTSTATIC(reflection_method_ptr);
2938 15 : GET_REFLECTION_OBJECT_PTR(mptr);
2939 :
2940 15 : zend_reflection_class_factory(mptr->common.scope, return_value TSRMLS_CC);
2941 : }
2942 : /* }}} */
2943 :
2944 : /* {{{ proto public ReflectionClass ReflectionMethod::getPrototype()
2945 : Get the prototype */
2946 : ZEND_METHOD(reflection_method, getPrototype)
2947 0 : {
2948 : reflection_object *intern;
2949 : zend_function *mptr;
2950 :
2951 0 : METHOD_NOTSTATIC(reflection_method_ptr);
2952 0 : GET_REFLECTION_OBJECT_PTR(mptr);
2953 :
2954 0 : if (!mptr->common.prototype) {
2955 0 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
2956 : "Method %s::%s does not have a prototype", intern->ce->name, mptr->common.function_name);
2957 0 : return;
2958 : }
2959 :
2960 0 : reflection_method_factory(mptr->common.prototype->common.scope, mptr->common.prototype, NULL, return_value TSRMLS_CC);
2961 : }
2962 : /* }}} */
2963 :
2964 : /* {{{ proto public void ReflectionMethod::setAccessible(bool visible)
2965 : Sets whether non-public methods can be invoked */
2966 : ZEND_METHOD(reflection_method, setAccessible)
2967 0 : {
2968 : reflection_object *intern;
2969 : zend_bool visible;
2970 :
2971 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &visible) == FAILURE) {
2972 0 : return;
2973 : }
2974 :
2975 0 : intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
2976 :
2977 0 : if (intern == NULL) {
2978 0 : return;
2979 : }
2980 :
2981 0 : intern->ignore_visibility = visible;
2982 : }
2983 : /* }}} */
2984 :
2985 : /* {{{ proto public static mixed ReflectionClass::export(mixed argument [, bool return]) throws ReflectionException
2986 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
2987 : ZEND_METHOD(reflection_class, export)
2988 6 : {
2989 6 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_class_ptr, 1);
2990 6 : }
2991 : /* }}} */
2992 :
2993 : /* {{{ reflection_class_object_ctor */
2994 : static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_object)
2995 469 : {
2996 : zval *argument;
2997 : zval *object;
2998 : zval *classname;
2999 : reflection_object *intern;
3000 : zend_class_entry **ce;
3001 :
3002 469 : if (is_object) {
3003 94 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &argument) == FAILURE) {
3004 7 : return;
3005 : }
3006 : } else {
3007 375 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &argument) == FAILURE) {
3008 2 : return;
3009 : }
3010 : }
3011 :
3012 460 : object = getThis();
3013 460 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
3014 460 : if (intern == NULL) {
3015 0 : return;
3016 : }
3017 :
3018 460 : if (Z_TYPE_P(argument) == IS_OBJECT) {
3019 101 : MAKE_STD_ZVAL(classname);
3020 101 : ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1);
3021 101 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL);
3022 101 : intern->ptr = Z_OBJCE_P(argument);
3023 101 : if (is_object) {
3024 87 : intern->obj = argument;
3025 87 : zval_add_ref(&argument);
3026 : }
3027 : } else {
3028 359 : convert_to_string_ex(&argument);
3029 359 : if (zend_lookup_class(Z_STRVAL_P(argument), Z_STRLEN_P(argument), &ce TSRMLS_CC) == FAILURE) {
3030 8 : if (!EG(exception)) {
3031 8 : zend_throw_exception_ex(reflection_exception_ptr, -1 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(argument));
3032 : }
3033 8 : return;
3034 : }
3035 :
3036 351 : MAKE_STD_ZVAL(classname);
3037 351 : ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1);
3038 351 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL);
3039 :
3040 351 : intern->ptr = *ce;
3041 : }
3042 452 : intern->ref_type = REF_TYPE_OTHER;
3043 : }
3044 : /* }}} */
3045 :
3046 : /* {{{ proto public void ReflectionClass::__construct(mixed argument) throws ReflectionException
3047 : Constructor. Takes a string or an instance as an argument */
3048 : ZEND_METHOD(reflection_class, __construct)
3049 375 : {
3050 375 : reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3051 375 : }
3052 : /* }}} */
3053 :
3054 : /* {{{ proto public array ReflectionClass::getStaticProperties()
3055 : Returns an associative array containing all static property values of the class */
3056 : ZEND_METHOD(reflection_class, getStaticProperties)
3057 20 : {
3058 : reflection_object *intern;
3059 : zend_class_entry *ce;
3060 : HashPosition pos;
3061 : zval **value;
3062 :
3063 20 : if (zend_parse_parameters_none() == FAILURE) {
3064 4 : return;
3065 : }
3066 :
3067 16 : GET_REFLECTION_OBJECT_PTR(ce);
3068 :
3069 16 : zend_update_class_constants(ce TSRMLS_CC);
3070 :
3071 16 : array_init(return_value);
3072 :
3073 16 : zend_hash_internal_pointer_reset_ex(CE_STATIC_MEMBERS(ce), &pos);
3074 :
3075 84 : while (zend_hash_get_current_data_ex(CE_STATIC_MEMBERS(ce), (void **) &value, &pos) == SUCCESS) {
3076 : uint key_len;
3077 : char *key;
3078 : ulong num_index;
3079 :
3080 52 : if (zend_hash_get_current_key_ex(CE_STATIC_MEMBERS(ce), &key, &key_len, &num_index, 0, &pos) != FAILURE && key) {
3081 : char *prop_name, *class_name;
3082 : zval *prop_copy;
3083 :
3084 52 : zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
3085 :
3086 : /* filter privates from base classes */
3087 52 : if (!(class_name && class_name[0] != '*' && strcmp(class_name, ce->name))) {
3088 : /* copy: enforce read only access */
3089 41 : ALLOC_ZVAL(prop_copy);
3090 41 : *prop_copy = **value;
3091 41 : zval_copy_ctor(prop_copy);
3092 41 : INIT_PZVAL(prop_copy);
3093 :
3094 41 : add_assoc_zval(return_value, prop_name, prop_copy);
3095 : }
3096 : }
3097 52 : zend_hash_move_forward_ex(CE_STATIC_MEMBERS(ce), &pos);
3098 : }
3099 : }
3100 : /* }}} */
3101 :
3102 : /* {{{ proto public mixed ReflectionClass::getStaticPropertyValue(string name [, mixed default])
3103 : Returns the value of a static property */
3104 : ZEND_METHOD(reflection_class, getStaticPropertyValue)
3105 31 : {
3106 : reflection_object *intern;
3107 : zend_class_entry *ce;
3108 : char *name;
3109 : int name_len;
3110 31 : zval **prop, *def_value = NULL;
3111 :
3112 31 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &name, &name_len, &def_value) == FAILURE) {
3113 3 : return;
3114 : }
3115 :
3116 28 : GET_REFLECTION_OBJECT_PTR(ce);
3117 :
3118 28 : zend_update_class_constants(ce TSRMLS_CC);
3119 28 : prop = zend_std_get_static_property(ce, name, name_len, 1 TSRMLS_CC);
3120 28 : if (!prop) {
3121 12 : if (def_value) {
3122 3 : RETURN_ZVAL(def_value, 1, 0);
3123 : } else {
3124 9 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
3125 : "Class %s does not have a property named %s", ce->name, name);
3126 : }
3127 9 : return;
3128 : } else {
3129 16 : RETURN_ZVAL(*prop, 1, 0);
3130 : }
3131 : }
3132 : /* }}} */
3133 :
3134 : /* {{{ proto public void ReflectionClass::setStaticPropertyValue($name, $value)
3135 : Sets the value of a static property */
3136 : ZEND_METHOD(reflection_class, setStaticPropertyValue)
3137 18 : {
3138 : reflection_object *intern;
3139 : zend_class_entry *ce;
3140 : char *name;
3141 : int name_len;
3142 : zval **variable_ptr, *value;
3143 : int refcount;
3144 : zend_uchar is_ref;
3145 :
3146 18 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &name_len, &value) == FAILURE) {
3147 4 : return;
3148 : }
3149 :
3150 14 : GET_REFLECTION_OBJECT_PTR(ce);
3151 :
3152 14 : zend_update_class_constants(ce TSRMLS_CC);
3153 14 : variable_ptr = zend_std_get_static_property(ce, name, name_len, 1 TSRMLS_CC);
3154 14 : if (!variable_ptr) {
3155 4 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
3156 : "Class %s does not have a property named %s", ce->name, name);
3157 4 : return;
3158 : }
3159 10 : refcount = Z_REFCOUNT_PP(variable_ptr);
3160 10 : is_ref = Z_ISREF_PP(variable_ptr);
3161 10 : zval_dtor(*variable_ptr);
3162 10 : **variable_ptr = *value;
3163 10 : zval_copy_ctor(*variable_ptr);
3164 10 : Z_SET_REFCOUNT_PP(variable_ptr, refcount);
3165 10 : Z_SET_ISREF_TO_PP(variable_ptr, is_ref);
3166 :
3167 : }
3168 : /* }}} */
3169 :
3170 : /* {{{ proto public array ReflectionClass::getDefaultProperties()
3171 : Returns an associative array containing copies of all default property values of the class */
3172 : ZEND_METHOD(reflection_class, getDefaultProperties)
3173 16 : {
3174 : reflection_object *intern;
3175 : zend_class_entry *ce;
3176 : int count, i;
3177 : HashTable *ht_list[3];
3178 :
3179 16 : if (zend_parse_parameters_none() == FAILURE) {
3180 4 : return;
3181 : }
3182 12 : GET_REFLECTION_OBJECT_PTR(ce);
3183 12 : array_init(return_value);
3184 :
3185 12 : zend_update_class_constants(ce TSRMLS_CC);
3186 :
3187 12 : ht_list[0] = CE_STATIC_MEMBERS(ce);
3188 12 : ht_list[1] = &ce->default_properties;
3189 12 : ht_list[2] = NULL;
3190 :
3191 36 : for (i = 0; ht_list[i] != NULL; i++) {
3192 :
3193 24 : count = zend_hash_num_elements(ht_list[i]);
3194 24 : if (count > 0) {
3195 : HashPosition pos;
3196 : zval **prop;
3197 :
3198 17 : zend_hash_internal_pointer_reset_ex(ht_list[i], &pos);
3199 135 : while (zend_hash_get_current_data_ex(ht_list[i], (void **) &prop, &pos) == SUCCESS) {
3200 : char *key, *class_name, *prop_name;
3201 : uint key_len;
3202 : ulong num_index;
3203 : zval *prop_copy;
3204 :
3205 101 : zend_hash_get_current_key_ex(ht_list[i], &key, &key_len, &num_index, 0, &pos);
3206 101 : zend_hash_move_forward_ex(ht_list[i], &pos);
3207 101 : zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name);
3208 101 : if (class_name && class_name[0] != '*' && strcmp(class_name, ce->name)) {
3209 : /* filter privates from base classes */
3210 13 : continue;
3211 : }
3212 :
3213 : /* copy: enforce read only access */
3214 88 : ALLOC_ZVAL(prop_copy);
3215 88 : *prop_copy = **prop;
3216 88 : zval_copy_ctor(prop_copy);
3217 88 : INIT_PZVAL(prop_copy);
3218 :
3219 88 : add_assoc_zval(return_value, prop_name, prop_copy);
3220 : }
3221 : }
3222 : }
3223 : }
3224 : /* }}} */
3225 :
3226 : /* {{{ proto public string ReflectionClass::__toString()
3227 : Returns a string representation */
3228 : ZEND_METHOD(reflection_class, __toString)
3229 31 : {
3230 : reflection_object *intern;
3231 : zend_class_entry *ce;
3232 : string str;
3233 :
3234 31 : if (zend_parse_parameters_none() == FAILURE) {
3235 0 : return;
3236 : }
3237 31 : GET_REFLECTION_OBJECT_PTR(ce);
3238 31 : string_init(&str);
3239 31 : _class_string(&str, ce, intern->obj, "" TSRMLS_CC);
3240 31 : RETURN_STRINGL(str.string, str.len - 1, 0);
3241 : }
3242 : /* }}} */
3243 :
3244 : /* {{{ proto public string ReflectionClass::getName()
3245 : Returns the class' name */
3246 : ZEND_METHOD(reflection_class, getName)
3247 74 : {
3248 74 : if (zend_parse_parameters_none() == FAILURE) {
3249 5 : return;
3250 : }
3251 69 : _default_get_entry(getThis(), "name", sizeof("name"), return_value TSRMLS_CC);
3252 : }
3253 : /* }}} */
3254 :
3255 : /* {{{ proto public bool ReflectionClass::isInternal()
3256 : Returns whether this class is an internal class */
3257 : ZEND_METHOD(reflection_class, isInternal)
3258 18 : {
3259 : reflection_object *intern;
3260 : zend_class_entry *ce;
3261 :
3262 18 : if (zend_parse_parameters_none() == FAILURE) {
3263 4 : return;
3264 : }
3265 14 : GET_REFLECTION_OBJECT_PTR(ce);
3266 14 : RETURN_BOOL(ce->type == ZEND_INTERNAL_CLASS);
3267 : }
3268 : /* }}} */
3269 :
3270 : /* {{{ proto public bool ReflectionClass::isUserDefined()
3271 : Returns whether this class is user-defined */
3272 : ZEND_METHOD(reflection_class, isUserDefined)
3273 18 : {
3274 : reflection_object *intern;
3275 : zend_class_entry *ce;
3276 :
3277 18 : if (zend_parse_parameters_none() == FAILURE) {
3278 4 : return;
3279 : }
3280 14 : GET_REFLECTION_OBJECT_PTR(ce);
3281 14 : RETURN_BOOL(ce->type == ZEND_USER_CLASS);
3282 : }
3283 : /* }}} */
3284 :
3285 : /* {{{ proto public string ReflectionClass::getFileName()
3286 : Returns the filename of the file this class was declared in */
3287 : ZEND_METHOD(reflection_class, getFileName)
3288 10 : {
3289 : reflection_object *intern;
3290 : zend_class_entry *ce;
3291 :
3292 10 : if (zend_parse_parameters_none() == FAILURE) {
3293 4 : return;
3294 : }
3295 6 : GET_REFLECTION_OBJECT_PTR(ce);
3296 6 : if (ce->type == ZEND_USER_CLASS) {
3297 4 : RETURN_STRING(ce->filename, 1);
3298 : }
3299 2 : RETURN_FALSE;
3300 : }
3301 : /* }}} */
3302 :
3303 : /* {{{ proto public int ReflectionClass::getStartLine()
3304 : Returns the line this class' declaration starts at */
3305 : ZEND_METHOD(reflection_class, getStartLine)
3306 12 : {
3307 : reflection_object *intern;
3308 : zend_class_entry *ce;
3309 :
3310 12 : if (zend_parse_parameters_none() == FAILURE) {
3311 4 : return;
3312 : }
3313 8 : GET_REFLECTION_OBJECT_PTR(ce);
3314 8 : if (ce->type == ZEND_USER_FUNCTION) {
3315 6 : RETURN_LONG(ce->line_start);
3316 : }
3317 2 : RETURN_FALSE;
3318 : }
3319 : /* }}} */
3320 :
3321 : /* {{{ proto public int ReflectionClass::getEndLine()
3322 : Returns the line this class' declaration ends at */
3323 : ZEND_METHOD(reflection_class, getEndLine)
3324 10 : {
3325 : reflection_object *intern;
3326 : zend_class_entry *ce;
3327 :
3328 10 : if (zend_parse_parameters_none() == FAILURE) {
3329 4 : return;
3330 : }
3331 6 : GET_REFLECTION_OBJECT_PTR(ce);
3332 6 : if (ce->type == ZEND_USER_CLASS) {
3333 4 : RETURN_LONG(ce->line_end);
3334 : }
3335 2 : RETURN_FALSE;
3336 : }
3337 : /* }}} */
3338 :
3339 : /* {{{ proto public string ReflectionClass::getDocComment()
3340 : Returns the doc comment for this class */
3341 : ZEND_METHOD(reflection_class, getDocComment)
3342 13 : {
3343 : reflection_object *intern;
3344 : zend_class_entry *ce;
3345 :
3346 13 : if (zend_parse_parameters_none() == FAILURE) {
3347 4 : return;
3348 : }
3349 9 : GET_REFLECTION_OBJECT_PTR(ce);
3350 9 : if (ce->type == ZEND_USER_CLASS && ce->doc_comment) {
3351 5 : RETURN_STRINGL(ce->doc_comment, ce->doc_comment_len, 1);
3352 : }
3353 4 : RETURN_FALSE;
3354 : }
3355 : /* }}} */
3356 :
3357 : /* {{{ proto public ReflectionMethod ReflectionClass::getConstructor()
3358 : Returns the class' constructor if there is one, NULL otherwise */
3359 : ZEND_METHOD(reflection_class, getConstructor)
3360 36 : {
3361 : reflection_object *intern;
3362 : zend_class_entry *ce;
3363 :
3364 36 : if (zend_parse_parameters_none() == FAILURE) {
3365 8 : return;
3366 : }
3367 28 : GET_REFLECTION_OBJECT_PTR(ce);
3368 :
3369 28 : if (ce->constructor) {
3370 23 : reflection_method_factory(ce, ce->constructor, NULL, return_value TSRMLS_CC);
3371 : } else {
3372 5 : RETURN_NULL();
3373 : }
3374 : }
3375 : /* }}} */
3376 :
3377 : /* {{{ proto public bool ReflectionClass::hasMethod(string name)
3378 : Returns whether a method exists or not */
3379 : ZEND_METHOD(reflection_class, hasMethod)
3380 39 : {
3381 : reflection_object *intern;
3382 : zend_class_entry *ce;
3383 : char *name, *lc_name;
3384 : int name_len;
3385 :
3386 39 : METHOD_NOTSTATIC(reflection_class_ptr);
3387 39 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
3388 4 : return;
3389 : }
3390 :
3391 35 : GET_REFLECTION_OBJECT_PTR(ce);
3392 35 : lc_name = zend_str_tolower_dup(name, name_len);
3393 35 : if (zend_hash_exists(&ce->function_table, lc_name, name_len + 1)) {
3394 24 : efree(lc_name);
3395 24 : RETURN_TRUE;
3396 : } else {
3397 11 : efree(lc_name);
3398 11 : RETURN_FALSE;
3399 : }
3400 : }
3401 : /* }}} */
3402 :
3403 : /* {{{ proto public ReflectionMethod ReflectionClass::getMethod(string name) throws ReflectionException
3404 : Returns the class' method specified by its name */
3405 : ZEND_METHOD(reflection_class, getMethod)
3406 39 : {
3407 : reflection_object *intern;
3408 : zend_class_entry *ce;
3409 : zend_function *mptr;
3410 : char *name, *lc_name;
3411 : int name_len;
3412 :
3413 39 : METHOD_NOTSTATIC(reflection_class_ptr);
3414 39 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
3415 4 : return;
3416 : }
3417 :
3418 35 : GET_REFLECTION_OBJECT_PTR(ce);
3419 35 : lc_name = zend_str_tolower_dup(name, name_len);
3420 36 : if (ce == zend_ce_closure && intern->obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3421 : && memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3422 : && (mptr = zend_get_closure_invoke_method(intern->obj TSRMLS_CC)) != NULL)
3423 : {
3424 : /* don't assign closure_object since we only reflect the invoke handler
3425 : method and not the closure definition itself */
3426 1 : reflection_method_factory(ce, mptr, NULL, return_value TSRMLS_CC);
3427 1 : efree(lc_name);
3428 34 : } else if (zend_hash_find(&ce->function_table, lc_name, name_len + 1, (void**) &mptr) == SUCCESS) {
3429 24 : reflection_method_factory(ce, mptr, NULL, return_value TSRMLS_CC);
3430 24 : efree(lc_name);
3431 : } else {
3432 10 : efree(lc_name);
3433 10 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
3434 : "Method %s does not exist", name);
3435 10 : return;
3436 : }
3437 : }
3438 : /* }}} */
3439 :
3440 : /* {{{ _addmethod */
3441 : static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, long filter, zval *obj TSRMLS_DC)
3442 252 : {
3443 : zval *method;
3444 252 : uint len = strlen(mptr->common.function_name);
3445 : zend_function *closure;
3446 :
3447 252 : if (mptr->common.fn_flags & filter) {
3448 232 : ALLOC_ZVAL(method);
3449 232 : if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3450 : && memcmp(mptr->common.function_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3451 : && (closure = zend_get_closure_invoke_method(obj TSRMLS_CC)) != NULL)
3452 : {
3453 1 : mptr = closure;
3454 : }
3455 : /* don't assign closure_object since we only reflect the invoke handler
3456 : method and not the closure definition itself, even if we have a
3457 : closure */
3458 232 : reflection_method_factory(ce, mptr, NULL, method TSRMLS_CC);
3459 232 : add_next_index_zval(retval, method);
3460 : }
3461 252 : }
3462 : /* }}} */
3463 :
3464 : /* {{{ _addmethod */
3465 : static int _addmethod_va(zend_function *mptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
3466 251 : {
3467 251 : zend_class_entry *ce = *va_arg(args, zend_class_entry**);
3468 251 : zval *retval = va_arg(args, zval*);
3469 251 : long filter = va_arg(args, long);
3470 251 : zval *obj = va_arg(args, zval *);
3471 :
3472 251 : _addmethod(mptr, ce, retval, filter, obj TSRMLS_CC);
3473 251 : return ZEND_HASH_APPLY_KEEP;
3474 : }
3475 : /* }}} */
3476 :
3477 : /* {{{ proto public ReflectionMethod[] ReflectionClass::getMethods([long $filter])
3478 : Returns an array of this class' methods */
3479 : ZEND_METHOD(reflection_class, getMethods)
3480 37 : {
3481 : reflection_object *intern;
3482 : zend_class_entry *ce;
3483 37 : long filter = 0;
3484 37 : int argc = ZEND_NUM_ARGS();
3485 :
3486 37 : METHOD_NOTSTATIC(reflection_class_ptr);
3487 37 : if (argc) {
3488 7 : if (zend_parse_parameters(argc TSRMLS_CC, "|l", &filter) == FAILURE) {
3489 2 : return;
3490 : }
3491 : } else {
3492 : /* No parameters given, default to "return all" */
3493 30 : filter = ZEND_ACC_PPP_MASK | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL | ZEND_ACC_STATIC;
3494 : }
3495 :
3496 35 : GET_REFLECTION_OBJECT_PTR(ce);
3497 :
3498 35 : array_init(return_value);
3499 35 : zend_hash_apply_with_arguments(&ce->function_table TSRMLS_CC, (apply_func_args_t) _addmethod_va, 4, &ce, return_value, filter, intern->obj);
3500 35 : if (intern->obj && instanceof_function(ce, zend_ce_closure TSRMLS_CC)) {
3501 1 : zend_function *closure = zend_get_closure_invoke_method(intern->obj TSRMLS_CC);
3502 1 : if (closure) {
3503 1 : _addmethod(closure, ce, return_value, filter, intern->obj TSRMLS_CC);
3504 1 : _free_function(closure TSRMLS_CC);
3505 : }
3506 : }
3507 : }
3508 : /* }}} */
3509 :
3510 : /* {{{ proto public bool ReflectionClass::hasProperty(string name)
3511 : Returns whether a property exists or not */
3512 : ZEND_METHOD(reflection_class, hasProperty)
3513 43 : {
3514 : reflection_object *intern;
3515 : zend_property_info *property_info;
3516 : zend_class_entry *ce;
3517 : char *name;
3518 : int name_len;
3519 : zval *property;
3520 :
3521 43 : METHOD_NOTSTATIC(reflection_class_ptr);
3522 43 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
3523 4 : return;
3524 : }
3525 :
3526 39 : GET_REFLECTION_OBJECT_PTR(ce);
3527 39 : if (zend_hash_find(&ce->properties_info, name, name_len+1, (void **) &property_info) == SUCCESS) {
3528 20 : if (property_info->flags & ZEND_ACC_SHADOW) {
3529 2 : RETURN_FALSE;
3530 : }
3531 18 : RETURN_TRUE;
3532 : } else {
3533 19 : if (intern->obj && Z_OBJ_HANDLER_P(intern->obj, has_property)) {
3534 2 : MAKE_STD_ZVAL(property);
3535 2 : ZVAL_STRINGL(property, name, name_len, 1);
3536 2 : if (Z_OBJ_HANDLER_P(intern->obj, has_property)(intern->obj, property, 2 TSRMLS_CC)) {
3537 0 : zval_ptr_dtor(&property);
3538 0 : RETURN_TRUE;
3539 : }
3540 2 : zval_ptr_dtor(&property);
3541 : }
3542 19 : RETURN_FALSE;
3543 : }
3544 : }
3545 : /* }}} */
3546 :
3547 : /* {{{ proto public ReflectionProperty ReflectionClass::getProperty(string name) throws ReflectionException
3548 : Returns the class' property specified by its name */
3549 : ZEND_METHOD(reflection_class, getProperty)
3550 102 : {
3551 : reflection_object *intern;
3552 : zend_class_entry *ce, **pce;
3553 : zend_property_info *property_info;
3554 : char *name, *tmp, *classname;
3555 : int name_len, classname_len;
3556 :
3557 102 : METHOD_NOTSTATIC(reflection_class_ptr);
3558 102 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
3559 4 : return;
3560 : }
3561 :
3562 98 : GET_REFLECTION_OBJECT_PTR(ce);
3563 98 : if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS) {
3564 45 : if ((property_info->flags & ZEND_ACC_SHADOW) == 0) {
3565 39 : reflection_property_factory(ce, property_info, return_value TSRMLS_CC);
3566 39 : return;
3567 : }
3568 53 : } else if (intern->obj) {
3569 : /* Check for dynamic properties */
3570 2 : if (zend_hash_exists(Z_OBJ_HT_P(intern->obj)->get_properties(intern->obj TSRMLS_CC), name, name_len+1)) {
3571 : zend_property_info property_info_tmp;
3572 2 : property_info_tmp.flags = ZEND_ACC_IMPLICIT_PUBLIC;
3573 2 : property_info_tmp.name = name;
3574 2 : property_info_tmp.name_length = name_len;
3575 2 : property_info_tmp.h = zend_get_hash_value(name, name_len+1);
3576 2 : property_info_tmp.doc_comment = NULL;
3577 2 : property_info_tmp.ce = ce;
3578 :
3579 2 : reflection_property_factory(ce, &property_info_tmp, return_value TSRMLS_CC);
3580 2 : return;
3581 : }
3582 : }
3583 57 : if ((tmp = strstr(name, "::")) != NULL) {
3584 33 : classname_len = tmp - name;
3585 33 : classname = zend_str_tolower_dup(name, classname_len);
3586 33 : classname[classname_len] = '\0';
3587 33 : name_len = name_len - (classname_len + 2);
3588 33 : name = tmp + 2;
3589 :
3590 33 : if (zend_lookup_class(classname, classname_len, &pce TSRMLS_CC) == FAILURE) {
3591 3 : if (!EG(exception)) {
3592 3 : zend_throw_exception_ex(reflection_exception_ptr, -1 TSRMLS_CC, "Class %s does not exist", classname);
3593 : }
3594 3 : efree(classname);
3595 3 : return;
3596 : }
3597 30 : efree(classname);
3598 :
3599 30 : if (!instanceof_function(ce, *pce TSRMLS_CC)) {
3600 8 : zend_throw_exception_ex(reflection_exception_ptr, -1 TSRMLS_CC, "Fully qualified property name %s::%s does not specify a base class of %s", (*pce)->name, name, ce->name);
3601 8 : return;
3602 : }
3603 22 : ce = *pce;
3604 :
3605 22 : if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS && (property_info->flags & ZEND_ACC_SHADOW) == 0) {
3606 20 : reflection_property_factory(ce, property_info, return_value TSRMLS_CC);
3607 20 : return;
3608 : }
3609 : }
3610 26 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
3611 : "Property %s does not exist", name);
3612 : }
3613 : /* }}} */
3614 :
3615 : /* {{{ _addproperty */
3616 : static int _addproperty(zend_property_info *pptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
3617 100 : {
3618 : zval *property;
3619 100 : zend_class_entry *ce = *va_arg(args, zend_class_entry**);
3620 100 : zval *retval = va_arg(args, zval*);
3621 100 : long filter = va_arg(args, long);
3622 :
3623 100 : if (pptr->flags & ZEND_ACC_SHADOW) {
3624 3 : return 0;
3625 : }
3626 :
3627 97 : if (pptr->flags & filter) {
3628 77 : ALLOC_ZVAL(property);
3629 77 : reflection_property_factory(ce, pptr, property TSRMLS_CC);
3630 77 : add_next_index_zval(retval, property);
3631 : }
3632 97 : return 0;
3633 : }
3634 : /* }}} */
3635 :
3636 : /* {{{ _adddynproperty */
3637 : static int _adddynproperty(zval **pptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
3638 10 : {
3639 : zval *property;
3640 10 : zend_class_entry *ce = *va_arg(args, zend_class_entry**);
3641 10 : zval *retval = va_arg(args, zval*), member;
3642 :
3643 10 : if (hash_key->arKey[0] == '\0') {
3644 2 : return 0; /* non public cannot be dynamic */
3645 : }
3646 :
3647 8 : ZVAL_STRINGL(&member, hash_key->arKey, hash_key->nKeyLength-1, 0);
3648 8 : if (zend_get_property_info(ce, &member, 1 TSRMLS_CC) == &EG(std_property_info)) {
3649 8 : MAKE_STD_ZVAL(property);
3650 8 : reflection_property_factory(ce, &EG(std_property_info), property TSRMLS_CC);
3651 8 : add_next_index_zval(retval, property);
3652 : }
3653 8 : return 0;
3654 : }
3655 : /* }}} */
3656 :
3657 : /* {{{ proto public ReflectionProperty[] ReflectionClass::getProperties([long $filter])
3658 : Returns an array of this class' properties */
3659 : ZEND_METHOD(reflection_class, getProperties)
3660 27 : {
3661 : reflection_object *intern;
3662 : zend_class_entry *ce;
3663 27 : long filter = 0;
3664 27 : int argc = ZEND_NUM_ARGS();
3665 :
3666 27 : METHOD_NOTSTATIC(reflection_class_ptr);
3667 27 : if (argc) {
3668 7 : if (zend_parse_parameters(argc TSRMLS_CC, "|l", &filter) == FAILURE) {
3669 2 : return;
3670 : }
3671 : } else {
3672 : /* No parameters given, default to "return all" */
3673 20 : filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC;
3674 : }
3675 :
3676 25 : GET_REFLECTION_OBJECT_PTR(ce);
3677 :
3678 25 : array_init(return_value);
3679 25 : zend_hash_apply_with_arguments(&ce->properties_info TSRMLS_CC, (apply_func_args_t) _addproperty, 3, &ce, return_value, filter);
3680 :
3681 25 : if (intern->obj && (filter & ZEND_ACC_PUBLIC) != 0 && Z_OBJ_HT_P(intern->obj)->get_properties) {
3682 6 : HashTable *properties = Z_OBJ_HT_P(intern->obj)->get_properties(intern->obj TSRMLS_CC);
3683 6 : zend_hash_apply_with_arguments(properties TSRMLS_CC, (apply_func_args_t) _adddynproperty, 2, &ce, return_value);
3684 : }
3685 : }
3686 : /* }}} */
3687 :
3688 : /* {{{ proto public bool ReflectionClass::hasConstant(string name)
3689 : Returns whether a constant exists or not */
3690 : ZEND_METHOD(reflection_class, hasConstant)
3691 17 : {
3692 : reflection_object *intern;
3693 : zend_class_entry *ce;
3694 : char *name;
3695 : int name_len;
3696 :
3697 17 : METHOD_NOTSTATIC(reflection_class_ptr);
3698 17 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
3699 4 : return;
3700 : }
3701 :
3702 13 : GET_REFLECTION_OBJECT_PTR(ce);
3703 13 : if (zend_hash_exists(&ce->constants_table, name, name_len + 1)) {
3704 4 : RETURN_TRUE;
3705 : } else {
3706 9 : RETURN_FALSE;
3707 : }
3708 : }
3709 : /* }}} */
3710 :
3711 : /* {{{ proto public array ReflectionClass::getConstants()
3712 : Returns an associative array containing this class' constants and their values */
3713 : ZEND_METHOD(reflection_class, getConstants)
3714 23 : {
3715 : zval *tmp_copy;
3716 : reflection_object *intern;
3717 : zend_class_entry *ce;
3718 :
3719 23 : if (zend_parse_parameters_none() == FAILURE) {
3720 6 : return;
3721 : }
3722 17 : GET_REFLECTION_OBJECT_PTR(ce);
3723 17 : array_init(return_value);
3724 17 : zend_hash_apply_with_argument(&ce->constants_table, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC);
3725 17 : zend_hash_copy(Z_ARRVAL_P(return_value), &ce->constants_table, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_copy, sizeof(zval *));
3726 : }
3727 : /* }}} */
3728 :
3729 : /* {{{ proto public mixed ReflectionClass::getConstant(string name)
3730 : Returns the class' constant specified by its name */
3731 : ZEND_METHOD(reflection_class, getConstant)
3732 42 : {
3733 : reflection_object *intern;
3734 : zend_class_entry *ce;
3735 : zval **value;
3736 : char *name;
3737 : int name_len;
3738 :
3739 42 : METHOD_NOTSTATIC(reflection_class_ptr);
3740 42 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
3741 8 : return;
3742 : }
3743 :
3744 34 : GET_REFLECTION_OBJECT_PTR(ce);
3745 34 : zend_hash_apply_with_argument(&ce->constants_table, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC);
3746 34 : if (zend_hash_find(&ce->constants_table, name, name_len + 1, (void **) &value) == FAILURE) {
3747 22 : RETURN_FALSE;
3748 : }
3749 12 : *return_value = **value;
3750 12 : zval_copy_ctor(return_value);
3751 12 : INIT_PZVAL(return_value);
3752 : }
3753 : /* }}} */
3754 :
3755 : /* {{{ _class_check_flag */
3756 : static void _class_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
3757 37 : {
3758 : reflection_object *intern;
3759 : zend_class_entry *ce;
3760 :
3761 37 : if (zend_parse_parameters_none() == FAILURE) {
3762 3 : return;
3763 : }
3764 34 : GET_REFLECTION_OBJECT_PTR(ce);
3765 34 : RETVAL_BOOL(ce->ce_flags & mask);
3766 : }
3767 : /* }}} */
3768 :
3769 : /* {{{ proto public bool ReflectionClass::isInstantiable()
3770 : Returns whether this class is instantiable */
3771 : ZEND_METHOD(reflection_class, isInstantiable)
3772 55 : {
3773 : reflection_object *intern;
3774 : zend_class_entry *ce;
3775 :
3776 55 : if (zend_parse_parameters_none() == FAILURE) {
3777 4 : return;
3778 : }
3779 51 : GET_REFLECTION_OBJECT_PTR(ce);
3780 51 : if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS)) {
3781 7 : RETURN_FALSE;
3782 : }
3783 :
3784 : /* Basically, the class is instantiable. Though, if there is a constructor
3785 : * and it is not publicly accessible, it isn't! */
3786 44 : if (!ce->constructor) {
3787 29 : RETURN_TRUE;
3788 : }
3789 :
3790 15 : RETURN_BOOL(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC);
3791 : }
3792 : /* }}} */
3793 :
3794 : /* {{{ proto public bool ReflectionClass::isInterface()
3795 : Returns whether this is an interface or a class */
3796 : ZEND_METHOD(reflection_class, isInterface)
3797 13 : {
3798 13 : _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_INTERFACE);
3799 13 : }
3800 : /* }}} */
3801 :
3802 : /* {{{ proto public bool ReflectionClass::isFinal()
3803 : Returns whether this class is final */
3804 : ZEND_METHOD(reflection_class, isFinal)
3805 12 : {
3806 12 : _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL_CLASS);
3807 12 : }
3808 : /* }}} */
3809 :
3810 : /* {{{ proto public bool ReflectionClass::isAbstract()
3811 : Returns whether this class is abstract */
3812 : ZEND_METHOD(reflection_class, isAbstract)
3813 12 : {
3814 12 : _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
3815 12 : }
3816 : /* }}} */
3817 :
3818 : /* {{{ proto public int ReflectionClass::getModifiers()
3819 : Returns a bitfield of the access modifiers for this class */
3820 : ZEND_METHOD(reflection_class, getModifiers)
3821 20 : {
3822 : reflection_object *intern;
3823 : zend_class_entry *ce;
3824 :
3825 20 : if (zend_parse_parameters_none() == FAILURE) {
3826 1 : return;
3827 : }
3828 19 : GET_REFLECTION_OBJECT_PTR(ce);
3829 :
3830 19 : RETURN_LONG(ce->ce_flags);
3831 : }
3832 : /* }}} */
3833 :
3834 : /* {{{ proto public bool ReflectionClass::isInstance(stdclass object)
3835 : Returns whether the given object is an instance of this class */
3836 : ZEND_METHOD(reflection_class, isInstance)
3837 59 : {
3838 : reflection_object *intern;
3839 : zend_class_entry *ce;
3840 : zval *object;
3841 :
3842 59 : METHOD_NOTSTATIC(reflection_class_ptr);
3843 59 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) {
3844 14 : return;
3845 : }
3846 45 : GET_REFLECTION_OBJECT_PTR(ce);
3847 45 : RETURN_BOOL(HAS_CLASS_ENTRY(*object) && instanceof_function(Z_OBJCE_P(object), ce TSRMLS_CC));
3848 : }
3849 : /* }}} */
3850 :
3851 : /* {{{ proto public stdclass ReflectionClass::newInstance(mixed* args, ...)
3852 : Returns an instance of this class */
3853 : ZEND_METHOD(reflection_class, newInstance)
3854 46 : {
3855 46 : zval *retval_ptr = NULL;
3856 : reflection_object *intern;
3857 : zend_class_entry *ce;
3858 :
3859 46 : METHOD_NOTSTATIC(reflection_class_ptr);
3860 46 : GET_REFLECTION_OBJECT_PTR(ce);
3861 :
3862 : /* Run the constructor if there is one */
3863 46 : if (ce->constructor) {
3864 23 : zval ***params = NULL;
3865 23 : int num_args = 0;
3866 : zend_fcall_info fci;
3867 : zend_fcall_info_cache fcc;
3868 :
3869 23 : if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
3870 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name);
3871 2 : return;
3872 : }
3873 :
3874 21 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", ¶ms, &num_args) == FAILURE) {
3875 0 : if (params) {
3876 0 : efree(params);
3877 : }
3878 0 : RETURN_FALSE;
3879 : }
3880 :
3881 21 : object_init_ex(return_value, ce);
3882 :
3883 21 : fci.size = sizeof(fci);
3884 21 : fci.function_table = EG(function_table);
3885 21 : fci.function_name = NULL;
3886 21 : fci.symbol_table = NULL;
3887 21 : fci.object_ptr = return_value;
3888 21 : fci.retval_ptr_ptr = &retval_ptr;
3889 21 : fci.param_count = num_args;
3890 21 : fci.params = params;
3891 21 : fci.no_separation = 1;
3892 :
3893 21 : fcc.initialized = 1;
3894 21 : fcc.function_handler = ce->constructor;
3895 21 : fcc.calling_scope = EG(scope);
3896 21 : fcc.called_scope = Z_OBJCE_P(return_value);
3897 21 : fcc.object_ptr = return_value;
3898 :
3899 21 : if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
3900 1 : if (params) {
3901 1 : efree(params);
3902 : }
3903 1 : if (retval_ptr) {
3904 0 : zval_ptr_dtor(&retval_ptr);
3905 : }
3906 1 : zend_error(E_WARNING, "Invocation of %s's constructor failed", ce->name);
3907 1 : RETURN_NULL();
3908 : }
3909 20 : if (retval_ptr) {
3910 20 : zval_ptr_dtor(&retval_ptr);
3911 : }
3912 20 : if (params) {
3913 16 : efree(params);
3914 : }
3915 23 : } else if (!ZEND_NUM_ARGS()) {
3916 20 : object_init_ex(return_value, ce);
3917 : } else {
3918 3 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ce->name);
3919 : }
3920 : }
3921 : /* }}} */
3922 :
3923 : /* {{{ proto public stdclass ReflectionClass::newInstanceArgs([array args])
3924 : Returns an instance of this class */
3925 : ZEND_METHOD(reflection_class, newInstanceArgs)
3926 13 : {
3927 13 : zval *retval_ptr = NULL;
3928 : reflection_object *intern;
3929 : zend_class_entry *ce;
3930 13 : int argc = 0;
3931 : HashTable *args;
3932 :
3933 :
3934 13 : METHOD_NOTSTATIC(reflection_class_ptr);
3935 13 : GET_REFLECTION_OBJECT_PTR(ce);
3936 :
3937 13 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|h", &args) == FAILURE) {
3938 0 : return;
3939 : }
3940 13 : if (ZEND_NUM_ARGS() > 0) {
3941 6 : argc = args->nNumOfElements;
3942 : }
3943 :
3944 : /* Run the constructor if there is one */
3945 13 : if (ce->constructor) {
3946 11 : zval ***params = NULL;
3947 : zend_fcall_info fci;
3948 : zend_fcall_info_cache fcc;
3949 :
3950 11 : if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
3951 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name);
3952 2 : return;
3953 : }
3954 :
3955 9 : if (argc) {
3956 5 : params = safe_emalloc(sizeof(zval **), argc, 0);
3957 5 : zend_hash_apply_with_argument(args, (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC);
3958 5 : params -= argc;
3959 : }
3960 :
3961 9 : object_init_ex(return_value, ce);
3962 :
3963 9 : fci.size = sizeof(fci);
3964 9 : fci.function_table = EG(function_table);
3965 9 : fci.function_name = NULL;
3966 9 : fci.symbol_table = NULL;
3967 9 : fci.object_ptr = return_value;
3968 9 : fci.retval_ptr_ptr = &retval_ptr;
3969 9 : fci.param_count = argc;
3970 9 : fci.params = params;
3971 9 : fci.no_separation = 1;
3972 :
3973 9 : fcc.initialized = 1;
3974 9 : fcc.function_handler = ce->constructor;
3975 9 : fcc.calling_scope = EG(scope);
3976 9 : fcc.called_scope = Z_OBJCE_P(return_value);
3977 9 : fcc.object_ptr = return_value;
3978 :
3979 9 : if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
3980 1 : if (params) {
3981 1 : efree(params);
3982 : }
3983 1 : if (retval_ptr) {
3984 0 : zval_ptr_dtor(&retval_ptr);
3985 : }
3986 1 : zend_error(E_WARNING, "Invocation of %s's constructor failed", ce->name);
3987 1 : RETURN_NULL();
3988 : }
3989 8 : if (retval_ptr) {
3990 8 : zval_ptr_dtor(&retval_ptr);
3991 : }
3992 8 : if (params) {
3993 4 : efree(params);
3994 : }
3995 2 : } else if (!ZEND_NUM_ARGS()) {
3996 1 : object_init_ex(return_value, ce);
3997 : } else {
3998 1 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ce->name);
3999 : }
4000 : }
4001 : /* }}} */
4002 :
4003 : /* {{{ proto public ReflectionClass[] ReflectionClass::getInterfaces()
4004 : Returns an array of interfaces this class implements */
4005 : ZEND_METHOD(reflection_class, getInterfaces)
4006 25 : {
4007 : reflection_object *intern;
4008 : zend_class_entry *ce;
4009 :
4010 25 : if (zend_parse_parameters_none() == FAILURE) {
4011 4 : return;
4012 : }
4013 21 : GET_REFLECTION_OBJECT_PTR(ce);
4014 :
4015 : /* Return an empty array if this class implements no interfaces */
4016 21 : array_init(return_value);
4017 :
4018 21 : if (ce->num_interfaces) {
4019 : zend_uint i;
4020 :
4021 58 : for (i=0; i < ce->num_interfaces; i++) {
4022 : zval *interface;
4023 45 : ALLOC_ZVAL(interface);
4024 45 : zend_reflection_class_factory(ce->interfaces[i], interface TSRMLS_CC);
4025 45 : add_assoc_zval_ex(return_value, ce->interfaces[i]->name, ce->interfaces[i]->name_length + 1, interface);
4026 : }
4027 : }
4028 : }
4029 : /* }}} */
4030 :
4031 : /* {{{ proto public String[] ReflectionClass::getInterfaceNames()
4032 : Returns an array of names of interfaces this class implements */
4033 : ZEND_METHOD(reflection_class, getInterfaceNames)
4034 1 : {
4035 : reflection_object *intern;
4036 : zend_class_entry *ce;
4037 : zend_uint i;
4038 :
4039 1 : if (zend_parse_parameters_none() == FAILURE) {
4040 0 : return;
4041 : }
4042 1 : GET_REFLECTION_OBJECT_PTR(ce);
4043 :
4044 : /* Return an empty array if this class implements no interfaces */
4045 1 : array_init(return_value);
4046 :
4047 3 : for (i=0; i < ce->num_interfaces; i++) {
4048 2 : add_next_index_stringl(return_value, ce->interfaces[i]->name, ce->interfaces[i]->name_length, 1);
4049 : }
4050 : }
4051 : /* }}} */
4052 :
4053 : /* {{{ proto public ReflectionClass ReflectionClass::getParentClass()
4054 : Returns the class' parent class, or, if none exists, FALSE */
4055 : ZEND_METHOD(reflection_class, getParentClass)
4056 10 : {
4057 : reflection_object *intern;
4058 : zend_class_entry *ce;
4059 :
4060 10 : if (zend_parse_parameters_none() == FAILURE) {
4061 3 : return;
4062 : }
4063 7 : GET_REFLECTION_OBJECT_PTR(ce);
4064 :
4065 7 : if (ce->parent) {
4066 2 : zend_reflection_class_factory(ce->parent, return_value TSRMLS_CC);
4067 : } else {
4068 5 : RETURN_FALSE;
4069 : }
4070 : }
4071 : /* }}} */
4072 :
4073 : /* {{{ proto public bool ReflectionClass::isSubclassOf(string|ReflectionClass class)
4074 : Returns whether this class is a subclass of another class */
4075 : ZEND_METHOD(reflection_class, isSubclassOf)
4076 123 : {
4077 : reflection_object *intern, *argument;
4078 : zend_class_entry *ce, **pce, *class_ce;
4079 : zval *class_name;
4080 :
4081 123 : METHOD_NOTSTATIC(reflection_class_ptr);
4082 123 : GET_REFLECTION_OBJECT_PTR(ce);
4083 :
4084 123 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE) {
4085 8 : return;
4086 : }
4087 :
4088 115 : switch(class_name->type) {
4089 : case IS_STRING:
4090 49 : if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &pce TSRMLS_CC) == FAILURE) {
4091 4 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4092 : "Class %s does not exist", Z_STRVAL_P(class_name));
4093 4 : return;
4094 : }
4095 45 : class_ce = *pce;
4096 45 : break;
4097 : case IS_OBJECT:
4098 62 : if (instanceof_function(Z_OBJCE_P(class_name), reflection_class_ptr TSRMLS_CC)) {
4099 62 : argument = (reflection_object *) zend_object_store_get_object(class_name TSRMLS_CC);
4100 62 : if (argument == NULL || argument->ptr == NULL) {
4101 0 : zend_error(E_ERROR, "Internal error: Failed to retrieve the argument's reflection object");
4102 : /* Bails out */
4103 : }
4104 62 : class_ce = argument->ptr;
4105 62 : break;
4106 : }
4107 : /* no break */
4108 : default:
4109 4 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4110 : "Parameter one must either be a string or a ReflectionClass object");
4111 4 : return;
4112 : }
4113 :
4114 107 : RETURN_BOOL((ce != class_ce && instanceof_function(ce, class_ce TSRMLS_CC)));
4115 : }
4116 : /* }}} */
4117 :
4118 : /* {{{ proto public bool ReflectionClass::implementsInterface(string|ReflectionClass interface_name)
4119 : Returns whether this class is a subclass of another class */
4120 : ZEND_METHOD(reflection_class, implementsInterface)
4121 56 : {
4122 : reflection_object *intern, *argument;
4123 : zend_class_entry *ce, *interface_ce, **pce;
4124 : zval *interface;
4125 :
4126 56 : METHOD_NOTSTATIC(reflection_class_ptr);
4127 56 : GET_REFLECTION_OBJECT_PTR(ce);
4128 :
4129 56 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &interface) == FAILURE) {
4130 2 : return;
4131 : }
4132 :
4133 54 : switch(interface->type) {
4134 : case IS_STRING:
4135 27 : if (zend_lookup_class(Z_STRVAL_P(interface), Z_STRLEN_P(interface), &pce TSRMLS_CC) == FAILURE) {
4136 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4137 : "Interface %s does not exist", Z_STRVAL_P(interface));
4138 2 : return;
4139 : }
4140 25 : interface_ce = *pce;
4141 25 : break;
4142 : case IS_OBJECT:
4143 25 : if (instanceof_function(Z_OBJCE_P(interface), reflection_class_ptr TSRMLS_CC)) {
4144 25 : argument = (reflection_object *) zend_object_store_get_object(interface TSRMLS_CC);
4145 25 : if (argument == NULL || argument->ptr == NULL) {
4146 0 : zend_error(E_ERROR, "Internal error: Failed to retrieve the argument's reflection object");
4147 : /* Bails out */
4148 : }
4149 25 : interface_ce = argument->ptr;
4150 25 : break;
4151 : }
4152 : /* no break */
4153 : default:
4154 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4155 : "Parameter one must either be a string or a ReflectionClass object");
4156 2 : return;
4157 : }
4158 :
4159 50 : if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) {
4160 30 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4161 : "Interface %s is a Class", interface_ce->name);
4162 30 : return;
4163 : }
4164 20 : RETURN_BOOL(instanceof_function(ce, interface_ce TSRMLS_CC));
4165 : }
4166 : /* }}} */
4167 :
4168 : /* {{{ proto public bool ReflectionClass::isIterateable()
4169 : Returns whether this class is iterateable (can be used inside foreach) */
4170 : ZEND_METHOD(reflection_class, isIterateable)
4171 27 : {
4172 : reflection_object *intern;
4173 : zend_class_entry *ce;
4174 :
4175 27 : METHOD_NOTSTATIC(reflection_class_ptr);
4176 27 : GET_REFLECTION_OBJECT_PTR(ce);
4177 :
4178 27 : RETURN_BOOL(ce->get_iterator != NULL);
4179 : }
4180 : /* }}} */
4181 :
4182 : /* {{{ proto public ReflectionExtension|NULL ReflectionClass::getExtension()
4183 : Returns NULL or the extension the class belongs to */
4184 : ZEND_METHOD(reflection_class, getExtension)
4185 2 : {
4186 : reflection_object *intern;
4187 : zend_class_entry *ce;
4188 :
4189 2 : METHOD_NOTSTATIC(reflection_class_ptr);
4190 2 : GET_REFLECTION_OBJECT_PTR(ce);
4191 :
4192 2 : if (ce->module) {
4193 1 : reflection_extension_factory(return_value, ce->module->name TSRMLS_CC);
4194 : }
4195 : }
4196 : /* }}} */
4197 :
4198 : /* {{{ proto public string|false ReflectionClass::getExtensionName()
4199 : Returns false or the name of the extension the class belongs to */
4200 : ZEND_METHOD(reflection_class, getExtensionName)
4201 6 : {
4202 : reflection_object *intern;
4203 : zend_class_entry *ce;
4204 :
4205 6 : METHOD_NOTSTATIC(reflection_class_ptr);
4206 6 : GET_REFLECTION_OBJECT_PTR(ce);
4207 :
4208 6 : if (ce->module) {
4209 5 : RETURN_STRING(ce->module->name, 1);
4210 : } else {
4211 1 : RETURN_FALSE;
4212 : }
4213 : }
4214 : /* }}} */
4215 :
4216 : /* {{{ proto public bool ReflectionClass::inNamespace()
4217 : Returns whether this class is defined in namespace */
4218 : ZEND_METHOD(reflection_class, inNamespace)
4219 2 : {
4220 : zval **name;
4221 : char *colon;
4222 :
4223 2 : if (zend_parse_parameters_none() == FAILURE) {
4224 0 : return;
4225 : }
4226 2 : if (zend_hash_find(Z_OBJPROP_P(getThis()), "name", sizeof("name"), (void **) &name) == FAILURE) {
4227 0 : RETURN_FALSE;
4228 : }
4229 2 : if (Z_TYPE_PP(name) == IS_STRING
4230 : && (colon = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name)))
4231 : && colon > Z_STRVAL_PP(name))
4232 : {
4233 1 : RETURN_TRUE;
4234 : }
4235 1 : RETURN_FALSE;
4236 : }
4237 : /* }}} */
4238 :
4239 : /* {{{ proto public string ReflectionClass::getNamespaceName()
4240 : Returns the name of namespace where this class is defined */
4241 : ZEND_METHOD(reflection_class, getNamespaceName)
4242 2 : {
4243 : zval **name;
4244 : char *backslash;
4245 :
4246 2 : if (zend_parse_parameters_none() == FAILURE) {
4247 0 : return;
4248 : }
4249 2 : if (zend_hash_find(Z_OBJPROP_P(getThis()), "name", sizeof("name"), (void **) &name) == FAILURE) {
4250 0 : RETURN_FALSE;
4251 : }
4252 2 : if (Z_TYPE_PP(name) == IS_STRING
4253 : && (backslash = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name)))
4254 : && backslash > Z_STRVAL_PP(name))
4255 : {
4256 1 : RETURN_STRINGL(Z_STRVAL_PP(name), backslash - Z_STRVAL_PP(name), 1);
4257 : }
4258 1 : RETURN_EMPTY_STRING();
4259 : }
4260 : /* }}} */
4261 :
4262 : /* {{{ proto public string ReflectionClass::getShortName()
4263 : Returns the short name of the class (without namespace part) */
4264 : ZEND_METHOD(reflection_class, getShortName)
4265 2 : {
4266 : zval **name;
4267 : char *backslash;
4268 :
4269 2 : if (zend_parse_parameters_none() == FAILURE) {
4270 0 : return;
4271 : }
4272 2 : if (zend_hash_find(Z_OBJPROP_P(getThis()), "name", sizeof("name"), (void **) &name) == FAILURE) {
4273 0 : RETURN_FALSE;
4274 : }
4275 2 : if (Z_TYPE_PP(name) == IS_STRING
4276 : && (backslash = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name)))
4277 : && backslash > Z_STRVAL_PP(name))
4278 : {
4279 1 : RETURN_STRINGL(backslash + 1, Z_STRLEN_PP(name) - (backslash - Z_STRVAL_PP(name) + 1), 1);
4280 : }
4281 1 : RETURN_ZVAL(*name, 1, 0);
4282 : }
4283 : /* }}} */
4284 :
4285 : /* {{{ proto public static mixed ReflectionObject::export(mixed argument [, bool return]) throws ReflectionException
4286 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
4287 : ZEND_METHOD(reflection_object, export)
4288 4 : {
4289 4 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_object_ptr, 1);
4290 4 : }
4291 : /* }}} */
4292 :
4293 : /* {{{ proto public void ReflectionObject::__construct(mixed argument) throws ReflectionException
4294 : Constructor. Takes an instance as an argument */
4295 : ZEND_METHOD(reflection_object, __construct)
4296 94 : {
4297 94 : reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4298 94 : }
4299 : /* }}} */
4300 :
4301 : /* {{{ proto public static mixed ReflectionProperty::export(mixed class, string name [, bool return]) throws ReflectionException
4302 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
4303 : ZEND_METHOD(reflection_property, export)
4304 14 : {
4305 14 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_property_ptr, 2);
4306 14 : }
4307 : /* }}} */
4308 :
4309 : /* {{{ proto public void ReflectionProperty::__construct(mixed class, string name)
4310 : Constructor. Throws an Exception in case the given property does not exist */
4311 : ZEND_METHOD(reflection_property, __construct)
4312 86 : {
4313 : zval *propname, *classname;
4314 : char *name_str, *class_name, *prop_name;
4315 86 : int name_len, dynam_prop = 0;
4316 : zval *object;
4317 : reflection_object *intern;
4318 : zend_class_entry **pce;
4319 : zend_class_entry *ce;
4320 86 : zend_property_info *property_info = NULL;
4321 : property_reference *reference;
4322 :
4323 86 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) {
4324 3 : return;
4325 : }
4326 :
4327 83 : object = getThis();
4328 83 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
4329 83 : if (intern == NULL) {
4330 0 : return;
4331 : }
4332 :
4333 : /* Find the class entry */
4334 83 : switch (Z_TYPE_P(classname)) {
4335 : case IS_STRING:
4336 72 : if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) {
4337 3 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4338 : "Class %s does not exist", Z_STRVAL_P(classname));
4339 3 : return;
4340 : }
4341 69 : ce = *pce;
4342 69 : break;
4343 :
4344 : case IS_OBJECT:
4345 9 : ce = Z_OBJCE_P(classname);
4346 9 : break;
4347 :
4348 : default:
4349 2 : _DO_THROW("The parameter class is expected to be either a string or an object");
4350 : /* returns out of this function */
4351 : }
4352 :
4353 78 : if (zend_hash_find(&ce->properties_info, name_str, name_len + 1, (void **) &property_info) == FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) {
4354 : /* Check for dynamic properties */
4355 10 : if (property_info == NULL && Z_TYPE_P(classname) == IS_OBJECT && Z_OBJ_HT_P(classname)->get_properties) {
4356 3 : if (zend_hash_exists(Z_OBJ_HT_P(classname)->get_properties(classname TSRMLS_CC), name_str, name_len+1)) {
4357 2 : dynam_prop = 1;
4358 : }
4359 : }
4360 10 : if (dynam_prop == 0) {
4361 8 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Property %s::$%s does not exist", ce->name, name_str);
4362 8 : return;
4363 : }
4364 : }
4365 :
4366 70 : if (dynam_prop == 0 && (property_info->flags & ZEND_ACC_PRIVATE) == 0) {
4367 : /* we have to search the class hierarchy for this (implicit) public or protected property */
4368 55 : zend_class_entry *tmp_ce = ce;
4369 : zend_property_info *tmp_info;
4370 :
4371 110 : while (tmp_ce && zend_hash_find(&tmp_ce->properties_info, name_str, name_len + 1, (void **) &tmp_info) != SUCCESS) {
4372 0 : ce = tmp_ce;
4373 0 : property_info = tmp_info;
4374 0 : tmp_ce = tmp_ce->parent;
4375 : }
4376 : }
4377 :
4378 70 : MAKE_STD_ZVAL(classname);
4379 70 : MAKE_STD_ZVAL(propname);
4380 :
4381 70 : if (dynam_prop == 0) {
4382 68 : zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name);
4383 68 : ZVAL_STRINGL(classname, property_info->ce->name, property_info->ce->name_length, 1);
4384 68 : ZVAL_STRING(propname, prop_name, 1);
4385 : } else {
4386 2 : ZVAL_STRINGL(classname, ce->name, ce->name_length, 1);
4387 2 : ZVAL_STRINGL(propname, name_str, name_len, 1);
4388 : }
4389 70 : zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
4390 70 : zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &propname, sizeof(zval *), NULL);
4391 :
4392 70 : reference = (property_reference*) emalloc(sizeof(property_reference));
4393 70 : if (dynam_prop) {
4394 2 : reference->prop.flags = ZEND_ACC_IMPLICIT_PUBLIC;
4395 2 : reference->prop.name = Z_STRVAL_P(propname);
4396 2 : reference->prop.name_length = Z_STRLEN_P(propname);
4397 2 : reference->prop.h = zend_get_hash_value(name_str, name_len+1);
4398 2 : reference->prop.doc_comment = NULL;
4399 2 : reference->prop.ce = ce;
4400 : } else {
4401 68 : reference->prop = *property_info;
4402 : }
4403 70 : reference->ce = ce;
4404 70 : intern->ptr = reference;
4405 70 : intern->ref_type = REF_TYPE_PROPERTY;
4406 70 : intern->ce = ce;
4407 70 : intern->ignore_visibility = 0;
4408 : }
4409 : /* }}} */
4410 :
4411 : /* {{{ proto public string ReflectionProperty::__toString()
4412 : Returns a string representation */
4413 : ZEND_METHOD(reflection_property, __toString)
4414 13 : {
4415 : reflection_object *intern;
4416 : property_reference *ref;
4417 : string str;
4418 :
4419 13 : if (zend_parse_parameters_none() == FAILURE) {
4420 0 : return;
4421 : }
4422 13 : GET_REFLECTION_OBJECT_PTR(ref);
4423 13 : string_init(&str);
4424 13 : _property_string(&str, &ref->prop, NULL, "" TSRMLS_CC);
4425 13 : RETURN_STRINGL(str.string, str.len - 1, 0);
4426 : }
4427 : /* }}} */
4428 :
4429 : /* {{{ proto public string ReflectionProperty::getName()
4430 : Returns the class' name */
4431 : ZEND_METHOD(reflection_property, getName)
4432 85 : {
4433 85 : if (zend_parse_parameters_none() == FAILURE) {
4434 1 : return;
4435 : }
4436 84 : _default_get_entry(getThis(), "name", sizeof("name"), return_value TSRMLS_CC);
4437 : }
4438 : /* }}} */
4439 :
4440 : static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
4441 216 : {
4442 : reflection_object *intern;
4443 : property_reference *ref;
4444 :
4445 216 : if (zend_parse_parameters_none() == FAILURE) {
4446 6 : return;
4447 : }
4448 210 : GET_REFLECTION_OBJECT_PTR(ref);
4449 210 : RETURN_BOOL(ref->prop.flags & mask);
4450 : }
4451 :
4452 : /* {{{ proto public bool ReflectionProperty::isPublic()
4453 : Returns whether this property is public */
4454 : ZEND_METHOD(reflection_property, isPublic)
4455 47 : {
4456 47 : _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC);
4457 47 : }
4458 : /* }}} */
4459 :
4460 : /* {{{ proto public bool ReflectionProperty::isPrivate()
4461 : Returns whether this property is private */
4462 : ZEND_METHOD(reflection_property, isPrivate)
4463 41 : {
4464 41 : _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
4465 41 : }
4466 : /* }}} */
4467 :
4468 : /* {{{ proto public bool ReflectionProperty::isProtected()
4469 : Returns whether this property is protected */
4470 : ZEND_METHOD(reflection_property, isProtected)
4471 42 : {
4472 42 : _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
4473 42 : }
4474 : /* }}} */
4475 :
4476 : /* {{{ proto public bool ReflectionProperty::isStatic()
4477 : Returns whether this property is static */
4478 : ZEND_METHOD(reflection_property, isStatic)
4479 42 : {
4480 42 : _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
4481 42 : }
4482 : /* }}} */
4483 :
4484 : /* {{{ proto public bool ReflectionProperty::isDefault()
4485 : Returns whether this property is default (declared at compilation time). */
4486 : ZEND_METHOD(reflection_property, isDefault)
4487 44 : {
4488 44 : _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ~ZEND_ACC_IMPLICIT_PUBLIC);
4489 44 : }
4490 : /* }}} */
4491 :
4492 : /* {{{ proto public int ReflectionProperty::getModifiers()
4493 : Returns a bitfield of the access modifiers for this property */
4494 : ZEND_METHOD(reflection_property, getModifiers)
4495 53 : {
4496 : reflection_object *intern;
4497 : property_reference *ref;
4498 :
4499 53 : if (zend_parse_parameters_none() == FAILURE) {
4500 1 : return;
4501 : }
4502 52 : GET_REFLECTION_OBJECT_PTR(ref);
4503 :
4504 52 : RETURN_LONG(ref->prop.flags);
4505 : }
4506 : /* }}} */
4507 :
4508 : /* {{{ proto public mixed ReflectionProperty::getValue([stdclass object])
4509 : Returns this property's value */
4510 : ZEND_METHOD(reflection_property, getValue)
4511 76 : {
4512 : reflection_object *intern;
4513 : property_reference *ref;
4514 : zval *object, name;
4515 76 : zval **member = NULL, *member_p = NULL;
4516 :
4517 76 : METHOD_NOTSTATIC(reflection_property_ptr);
4518 76 : GET_REFLECTION_OBJECT_PTR(ref);
4519 :
4520 76 : if (!(ref->prop.flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) {
4521 29 : _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC);
4522 29 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4523 : "Cannot access non-public member %s::%s", intern->ce->name, Z_STRVAL(name));
4524 29 : zval_dtor(&name);
4525 29 : return;
4526 : }
4527 :
4528 47 : if ((ref->prop.flags & ZEND_ACC_STATIC)) {
4529 20 : zend_update_class_constants(intern->ce TSRMLS_CC);
4530 20 : if (zend_hash_quick_find(CE_STATIC_MEMBERS(intern->ce), ref->prop.name, ref->prop.name_length + 1, ref->prop.h, (void **) &member) == FAILURE) {
4531 0 : zend_error(E_ERROR, "Internal error: Could not find the property %s::%s", intern->ce->name, ref->prop.name);
4532 : /* Bails out */
4533 : }
4534 20 : *return_value= **member;
4535 20 : zval_copy_ctor(return_value);
4536 20 : INIT_PZVAL(return_value);
4537 : } else {
4538 : char *class_name, *prop_name;
4539 :
4540 27 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) {
4541 3 : return;
4542 : }
4543 24 : zend_unmangle_property_name(ref->prop.name, ref->prop.name_length, &class_name, &prop_name);
4544 24 : member_p = zend_read_property(ref->ce, object, prop_name, strlen(prop_name), 1 TSRMLS_CC);
4545 24 : *return_value= *member_p;
4546 24 : zval_copy_ctor(return_value);
4547 24 : INIT_PZVAL(return_value);
4548 24 : if (member_p != EG(uninitialized_zval_ptr)) {
4549 23 : zval_add_ref(&member_p);
4550 23 : zval_ptr_dtor(&member_p);
4551 : }
4552 : }
4553 : }
4554 : /* }}} */
4555 :
4556 : /* {{{ proto public void ReflectionProperty::setValue([stdclass object,] mixed value)
4557 : Sets this property's value */
4558 : ZEND_METHOD(reflection_property, setValue)
4559 21 : {
4560 : reflection_object *intern;
4561 : property_reference *ref;
4562 : zval **variable_ptr;
4563 : zval *object, name;
4564 : zval *value;
4565 21 : int setter_done = 0;
4566 : zval *tmp;
4567 : HashTable *prop_table;
4568 :
4569 21 : METHOD_NOTSTATIC(reflection_property_ptr);
4570 21 : GET_REFLECTION_OBJECT_PTR(ref);
4571 :
4572 21 : if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) {
4573 1 : _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC);
4574 1 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4575 : "Cannot access non-public member %s::%s", intern->ce->name, Z_STRVAL(name));
4576 1 : zval_dtor(&name);
4577 1 : return;
4578 : }
4579 :
4580 20 : if ((ref->prop.flags & ZEND_ACC_STATIC)) {
4581 10 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
4582 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &tmp, &value) == FAILURE) {
4583 2 : return;
4584 : }
4585 : }
4586 8 : zend_update_class_constants(intern->ce TSRMLS_CC);
4587 8 : prop_table = CE_STATIC_MEMBERS(intern->ce);
4588 :
4589 8 : if (zend_hash_quick_find(prop_table, ref->prop.name, ref->prop.name_length + 1, ref->prop.h, (void **) &variable_ptr) == FAILURE) {
4590 0 : zend_error(E_ERROR, "Internal error: Could not find the property %s::%s", intern->ce->name, ref->prop.name);
4591 : /* Bails out */
4592 : }
4593 8 : if (*variable_ptr == value) {
4594 0 : setter_done = 1;
4595 : } else {
4596 8 : if (PZVAL_IS_REF(*variable_ptr)) {
4597 3 : zval_dtor(*variable_ptr);
4598 3 : (*variable_ptr)->type = value->type;
4599 3 : (*variable_ptr)->value = value->value;
4600 3 : if (Z_REFCOUNT_P(value) > 0) {
4601 3 : zval_copy_ctor(*variable_ptr);
4602 : }
4603 3 : setter_done = 1;
4604 : }
4605 : }
4606 8 : if (!setter_done) {
4607 : zval **foo;
4608 :
4609 5 : Z_ADDREF_P(value);
4610 5 : if (PZVAL_IS_REF(value)) {
4611 0 : SEPARATE_ZVAL(&value);
4612 : }
4613 5 : zend_hash_quick_update(prop_table, ref->prop.name, ref->prop.name_length+1, ref->prop.h, &value, sizeof(zval *), (void **) &foo);
4614 : }
4615 : } else {
4616 : char *class_name, *prop_name;
4617 :
4618 10 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) {
4619 4 : return;
4620 : }
4621 6 : zend_unmangle_property_name(ref->prop.name, ref->prop.name_length, &class_name, &prop_name);
4622 6 : zend_update_property(ref->ce, object, prop_name, strlen(prop_name), value TSRMLS_CC);
4623 : }
4624 : }
4625 : /* }}} */
4626 :
4627 : /* {{{ proto public ReflectionClass ReflectionProperty::getDeclaringClass()
4628 : Get the declaring class */
4629 : ZEND_METHOD(reflection_property, getDeclaringClass)
4630 26 : {
4631 : reflection_object *intern;
4632 : property_reference *ref;
4633 : zend_class_entry *tmp_ce, *ce;
4634 : zend_property_info *tmp_info;
4635 : char *prop_name, *class_name;
4636 : int prop_name_len;
4637 :
4638 26 : if (zend_parse_parameters_none() == FAILURE) {
4639 1 : return;
4640 : }
4641 25 : GET_REFLECTION_OBJECT_PTR(ref);
4642 :
4643 25 : if (zend_unmangle_property_name(ref->prop.name, ref->prop.name_length, &class_name, &prop_name) != SUCCESS) {
4644 0 : RETURN_FALSE;
4645 : }
4646 :
4647 25 : prop_name_len = strlen(prop_name);
4648 25 : ce = tmp_ce = ref->ce;
4649 58 : while (tmp_ce && zend_hash_find(&tmp_ce->properties_info, prop_name, prop_name_len + 1, (void **) &tmp_info) == SUCCESS) {
4650 33 : if (tmp_info->flags & ZEND_ACC_PRIVATE || tmp_info->flags & ZEND_ACC_SHADOW) {
4651 : /* it's a private property, so it can't be inherited */
4652 : break;
4653 : }
4654 26 : ce = tmp_ce;
4655 26 : if (tmp_ce == tmp_info->ce) {
4656 : /* declared in this class, done */
4657 18 : break;
4658 : }
4659 8 : tmp_ce = tmp_ce->parent;
4660 : }
4661 :
4662 25 : zend_reflection_class_factory(ce, return_value TSRMLS_CC);
4663 : }
4664 : /* }}} */
4665 :
4666 : /* {{{ proto public string ReflectionProperty::getDocComment()
4667 : Returns the doc comment for this property */
4668 : ZEND_METHOD(reflection_property, getDocComment)
4669 22 : {
4670 : reflection_object *intern;
4671 : property_reference *ref;
4672 :
4673 22 : if (zend_parse_parameters_none() == FAILURE) {
4674 4 : return;
4675 : }
4676 18 : GET_REFLECTION_OBJECT_PTR(ref);
4677 18 : if (ref->prop.doc_comment) {
4678 9 : RETURN_STRINGL(ref->prop.doc_comment, ref->prop.doc_comment_len, 1);
4679 : }
4680 9 : RETURN_FALSE;
4681 : }
4682 : /* }}} */
4683 :
4684 : /* {{{ proto public int ReflectionProperty::setAccessible(bool visible)
4685 : Sets whether non-public properties can be requested */
4686 : ZEND_METHOD(reflection_property, setAccessible)
4687 12 : {
4688 : reflection_object *intern;
4689 : zend_bool visible;
4690 :
4691 12 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &visible) == FAILURE) {
4692 0 : return;
4693 : }
4694 :
4695 12 : intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC);
4696 :
4697 12 : if (intern == NULL) {
4698 0 : return;
4699 : }
4700 :
4701 12 : intern->ignore_visibility = visible;
4702 : }
4703 : /* }}} */
4704 :
4705 : /* {{{ proto public static mixed ReflectionExtension::export(string name [, bool return]) throws ReflectionException
4706 : Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
4707 : ZEND_METHOD(reflection_extension, export)
4708 2 : {
4709 2 : _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_extension_ptr, 1);
4710 2 : }
4711 : /* }}} */
4712 :
4713 : /* {{{ proto public void ReflectionExtension::__construct(string name)
4714 : Constructor. Throws an Exception in case the given extension does not exist */
4715 : ZEND_METHOD(reflection_extension, __construct)
4716 22 : {
4717 : zval *name;
4718 : zval *object;
4719 : char *lcname;
4720 : reflection_object *intern;
4721 : zend_module_entry *module;
4722 : char *name_str;
4723 : int name_len;
4724 : ALLOCA_FLAG(use_heap)
4725 :
4726 22 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) {
4727 1 : return;
4728 : }
4729 :
4730 21 : object = getThis();
4731 21 : intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
4732 21 : if (intern == NULL) {
4733 0 : return;
4734 : }
4735 21 : lcname = do_alloca(name_len + 1, use_heap);
4736 21 : zend_str_tolower_copy(lcname, name_str, name_len);
4737 21 : if (zend_hash_find(&module_registry, lcname, name_len + 1, (void **)&module) == FAILURE) {
4738 2 : free_alloca(lcname, use_heap);
4739 2 : zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
4740 : "Extension %s does not exist", name_str);
4741 2 : return;
|