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