PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 1ms

/ext/reflection/php_reflection.c

http://github.com/infusion/PHP
C | 5559 lines | 4223 code | 737 blank | 599 comment | 1019 complexity | 7204d8e86ad231fc5b03c4f8607f18b6 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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. /* $Id: php_reflection.c 307971 2011-02-03 12:45:30Z cataphract $ */
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "php.h"
  27. #include "php_ini.h"
  28. #include "php_reflection.h"
  29. #include "ext/standard/info.h"
  30. #include "zend.h"
  31. #include "zend_API.h"
  32. #include "zend_exceptions.h"
  33. #include "zend_operators.h"
  34. #include "zend_constants.h"
  35. #include "zend_ini.h"
  36. #include "zend_interfaces.h"
  37. #include "zend_closures.h"
  38. /* Undefine "getParameters" macro defined in "main/php3_compat.h" */
  39. #ifdef getParameters
  40. # undef getParameters
  41. #endif
  42. /* Class entry pointers */
  43. PHPAPI zend_class_entry *reflector_ptr;
  44. PHPAPI zend_class_entry *reflection_exception_ptr;
  45. PHPAPI zend_class_entry *reflection_ptr;
  46. PHPAPI zend_class_entry *reflection_function_abstract_ptr;
  47. PHPAPI zend_class_entry *reflection_function_ptr;
  48. PHPAPI zend_class_entry *reflection_parameter_ptr;
  49. PHPAPI zend_class_entry *reflection_class_ptr;
  50. PHPAPI zend_class_entry *reflection_object_ptr;
  51. PHPAPI zend_class_entry *reflection_method_ptr;
  52. PHPAPI zend_class_entry *reflection_property_ptr;
  53. PHPAPI zend_class_entry *reflection_extension_ptr;
  54. #if MBO_0
  55. ZEND_BEGIN_MODULE_GLOBALS(reflection)
  56. int dummy;
  57. ZEND_END_MODULE_GLOBALS(reflection)
  58. #ifdef ZTS
  59. # define REFLECTION_G(v) \
  60. TSRMG(reflection_globals_id, zend_reflection_globals*, v)
  61. extern int reflection_globals_id;
  62. #else
  63. # define REFLECTION_G(v) (reflection_globals.v)
  64. extern zend_reflection_globals reflectionglobals;
  65. #endif
  66. ZEND_DECLARE_MODULE_GLOBALS(reflection)
  67. #endif /* MBO_0 */
  68. /* Method macros */
  69. #define METHOD_NOTSTATIC(ce) \
  70. if (!this_ptr || !instanceof_function(Z_OBJCE_P(this_ptr), ce TSRMLS_CC)) { \
  71. php_error_docref(NULL TSRMLS_CC, E_ERROR, "%s() cannot be called statically", get_active_function_name(TSRMLS_C)); \
  72. return; \
  73. } \
  74. /* Exception throwing macro */
  75. #define _DO_THROW(msg) \
  76. zend_throw_exception(reflection_exception_ptr, msg, 0 TSRMLS_CC); \
  77. return; \
  78. #define RETURN_ON_EXCEPTION \
  79. if (EG(exception) && Z_OBJCE_P(EG(exception)) == reflection_exception_ptr) { \
  80. return; \
  81. }
  82. #define GET_REFLECTION_OBJECT_PTR(target) \
  83. intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC); \
  84. if (intern == NULL || intern->ptr == NULL) { \
  85. RETURN_ON_EXCEPTION \
  86. php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Failed to retrieve the reflection object"); \
  87. } \
  88. target = intern->ptr; \
  89. /* Class constants */
  90. #define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value) \
  91. zend_declare_class_constant_long(reflection_ ## class_name ## _ptr, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
  92. /* {{{ Smart string functions */
  93. typedef struct _string {
  94. char *string;
  95. int len;
  96. int alloced;
  97. } string;
  98. static void string_init(string *str)
  99. {
  100. str->string = (char *) emalloc(1024);
  101. str->len = 1;
  102. str->alloced = 1024;
  103. *str->string = '\0';
  104. }
  105. static string *string_printf(string *str, const char *format, ...)
  106. {
  107. int len;
  108. va_list arg;
  109. char *s_tmp;
  110. va_start(arg, format);
  111. len = zend_vspprintf(&s_tmp, 0, format, arg);
  112. if (len) {
  113. register int nlen = (str->len + len + (1024 - 1)) & ~(1024 - 1);
  114. if (str->alloced < nlen) {
  115. str->alloced = nlen;
  116. str->string = erealloc(str->string, str->alloced);
  117. }
  118. memcpy(str->string + str->len - 1, s_tmp, len + 1);
  119. str->len += len;
  120. }
  121. efree(s_tmp);
  122. va_end(arg);
  123. return str;
  124. }
  125. static string *string_write(string *str, char *buf, int len)
  126. {
  127. register int nlen = (str->len + len + (1024 - 1)) & ~(1024 - 1);
  128. if (str->alloced < nlen) {
  129. str->alloced = nlen;
  130. str->string = erealloc(str->string, str->alloced);
  131. }
  132. memcpy(str->string + str->len - 1, buf, len);
  133. str->len += len;
  134. str->string[str->len - 1] = '\0';
  135. return str;
  136. }
  137. static string *string_append(string *str, string *append)
  138. {
  139. if (append->len > 1) {
  140. string_write(str, append->string, append->len - 1);
  141. }
  142. return str;
  143. }
  144. static void string_free(string *str)
  145. {
  146. efree(str->string);
  147. str->len = 0;
  148. str->alloced = 0;
  149. str->string = NULL;
  150. }
  151. /* }}} */
  152. /* Struct for properties */
  153. typedef struct _property_reference {
  154. zend_class_entry *ce;
  155. zend_property_info prop;
  156. } property_reference;
  157. /* Struct for parameters */
  158. typedef struct _parameter_reference {
  159. zend_uint offset;
  160. zend_uint required;
  161. struct _zend_arg_info *arg_info;
  162. zend_function *fptr;
  163. } parameter_reference;
  164. typedef enum {
  165. REF_TYPE_OTHER, /* Must be 0 */
  166. REF_TYPE_FUNCTION,
  167. REF_TYPE_PARAMETER,
  168. REF_TYPE_PROPERTY,
  169. REF_TYPE_DYNAMIC_PROPERTY
  170. } reflection_type_t;
  171. /* Struct for reflection objects */
  172. typedef struct {
  173. zend_object zo;
  174. void *ptr;
  175. reflection_type_t ref_type;
  176. zval *obj;
  177. zend_class_entry *ce;
  178. unsigned int ignore_visibility:1;
  179. } reflection_object;
  180. static zend_object_handlers reflection_object_handlers;
  181. static void _default_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC)
  182. {
  183. zval **value;
  184. if (zend_hash_find(Z_OBJPROP_P(object), name, name_len, (void **) &value) == FAILURE) {
  185. RETURN_FALSE;
  186. }
  187. MAKE_COPY_ZVAL(value, return_value);
  188. }
  189. #ifdef ilia_0
  190. static void _default_lookup_entry(zval *object, char *name, int name_len, zval **return_value TSRMLS_DC) /* {{{ */
  191. {
  192. zval **value;
  193. if (zend_hash_find(Z_OBJPROP_P(object), name, name_len, (void **) &value) == FAILURE) {
  194. *return_value = NULL;
  195. } else {
  196. *return_value = *value;
  197. }
  198. }
  199. /* }}} */
  200. #endif
  201. static void reflection_register_implement(zend_class_entry *class_entry, zend_class_entry *interface_entry TSRMLS_DC)
  202. {
  203. zend_uint num_interfaces = ++class_entry->num_interfaces;
  204. class_entry->interfaces = (zend_class_entry **) realloc(class_entry->interfaces, sizeof(zend_class_entry *) * num_interfaces);
  205. class_entry->interfaces[num_interfaces - 1] = interface_entry;
  206. }
  207. static zend_function *_copy_function(zend_function *fptr TSRMLS_DC) /* {{{ */
  208. {
  209. if (fptr
  210. && fptr->type == ZEND_INTERNAL_FUNCTION
  211. && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
  212. {
  213. zend_function *copy_fptr;
  214. copy_fptr = emalloc(sizeof(zend_function));
  215. memcpy(copy_fptr, fptr, sizeof(zend_function));
  216. copy_fptr->internal_function.function_name = estrdup(fptr->internal_function.function_name);
  217. return copy_fptr;
  218. } else {
  219. /* no copy needed */
  220. return fptr;
  221. }
  222. }
  223. /* }}} */
  224. static void _free_function(zend_function *fptr TSRMLS_DC) /* {{{ */
  225. {
  226. if (fptr
  227. && fptr->type == ZEND_INTERNAL_FUNCTION
  228. && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
  229. {
  230. efree(fptr->internal_function.function_name);
  231. efree(fptr);
  232. }
  233. }
  234. /* }}} */
  235. static void reflection_free_objects_storage(void *object TSRMLS_DC)
  236. {
  237. reflection_object *intern = (reflection_object *) object;
  238. parameter_reference *reference;
  239. property_reference *prop_reference;
  240. if (intern->ptr) {
  241. switch (intern->ref_type) {
  242. case REF_TYPE_PARAMETER:
  243. reference = (parameter_reference*)intern->ptr;
  244. _free_function(reference->fptr TSRMLS_CC);
  245. efree(intern->ptr);
  246. break;
  247. case REF_TYPE_FUNCTION:
  248. _free_function(intern->ptr TSRMLS_CC);
  249. break;
  250. case REF_TYPE_PROPERTY:
  251. efree(intern->ptr);
  252. break;
  253. case REF_TYPE_DYNAMIC_PROPERTY:
  254. prop_reference = (property_reference*)intern->ptr;
  255. efree(prop_reference->prop.name);
  256. efree(intern->ptr);
  257. break;
  258. case REF_TYPE_OTHER:
  259. break;
  260. }
  261. }
  262. intern->ptr = NULL;
  263. if (intern->obj) {
  264. zval_ptr_dtor(&intern->obj);
  265. }
  266. zend_objects_free_object_storage(object TSRMLS_CC);
  267. }
  268. static zend_object_value reflection_objects_new(zend_class_entry *class_type TSRMLS_DC)
  269. {
  270. zval tmp;
  271. zend_object_value retval;
  272. reflection_object *intern;
  273. intern = ecalloc(1, sizeof(reflection_object));
  274. intern->zo.ce = class_type;
  275. zend_object_std_init(&intern->zo, class_type TSRMLS_CC);
  276. zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
  277. retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, NULL TSRMLS_CC);
  278. retval.handlers = &reflection_object_handlers;
  279. return retval;
  280. }
  281. static zval * reflection_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC)
  282. {
  283. if (!object) {
  284. ALLOC_ZVAL(object);
  285. }
  286. Z_TYPE_P(object) = IS_OBJECT;
  287. object_init_ex(object, pce);
  288. Z_SET_REFCOUNT_P(object, 1);
  289. Z_SET_ISREF_P(object);
  290. return object;
  291. }
  292. static void _const_string(string *str, char *name, zval *value, char *indent TSRMLS_DC);
  293. static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char *indent TSRMLS_DC);
  294. static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent TSRMLS_DC);
  295. static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC);
  296. static void _extension_string(string *str, zend_module_entry *module, char *indent TSRMLS_DC);
  297. /* {{{ _class_string */
  298. static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC)
  299. {
  300. int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0;
  301. string sub_indent;
  302. string_init(&sub_indent);
  303. string_printf(&sub_indent, "%s ", indent);
  304. /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
  305. if (ce->type == ZEND_USER_CLASS && ce->doc_comment) {
  306. string_printf(str, "%s%s", indent, ce->doc_comment);
  307. string_write(str, "\n", 1);
  308. }
  309. if (obj) {
  310. string_printf(str, "%sObject of class [ ", indent);
  311. } else {
  312. string_printf(str, "%s%s [ ", indent, (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : "Class");
  313. }
  314. string_printf(str, (ce->type == ZEND_USER_CLASS) ? "<user" : "<internal");
  315. if (ce->module) {
  316. string_printf(str, ":%s", ce->module->name);
  317. }
  318. string_printf(str, "> ");
  319. if (ce->get_iterator != NULL) {
  320. string_printf(str, "<iterateable> ");
  321. }
  322. if (ce->ce_flags & ZEND_ACC_INTERFACE) {
  323. string_printf(str, "interface ");
  324. } else {
  325. if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
  326. string_printf(str, "abstract ");
  327. }
  328. if (ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
  329. string_printf(str, "final ");
  330. }
  331. string_printf(str, "class ");
  332. }
  333. string_printf(str, "%s", ce->name);
  334. if (ce->parent) {
  335. string_printf(str, " extends %s", ce->parent->name);
  336. }
  337. if (ce->num_interfaces) {
  338. zend_uint i;
  339. if (ce->ce_flags & ZEND_ACC_INTERFACE) {
  340. string_printf(str, " extends %s", ce->interfaces[0]->name);
  341. } else {
  342. string_printf(str, " implements %s", ce->interfaces[0]->name);
  343. }
  344. for (i = 1; i < ce->num_interfaces; ++i) {
  345. string_printf(str, ", %s", ce->interfaces[i]->name);
  346. }
  347. }
  348. string_printf(str, " ] {\n");
  349. /* The information where a class is declared is only available for user classes */
  350. if (ce->type == ZEND_USER_CLASS) {
  351. string_printf(str, "%s @@ %s %d-%d\n", indent, ce->filename,
  352. ce->line_start, ce->line_end);
  353. }
  354. /* Constants */
  355. if (&ce->constants_table) {
  356. zend_hash_apply_with_argument(&ce->constants_table, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC);
  357. string_printf(str, "\n");
  358. count = zend_hash_num_elements(&ce->constants_table);
  359. string_printf(str, "%s - Constants [%d] {\n", indent, count);
  360. if (count > 0) {
  361. HashPosition pos;
  362. zval **value;
  363. char *key;
  364. uint key_len;
  365. ulong num_index;
  366. zend_hash_internal_pointer_reset_ex(&ce->constants_table, &pos);
  367. while (zend_hash_get_current_data_ex(&ce->constants_table, (void **) &value, &pos) == SUCCESS) {
  368. zend_hash_get_current_key_ex(&ce->constants_table, &key, &key_len, &num_index, 0, &pos);
  369. _const_string(str, key, *value, indent TSRMLS_CC);
  370. zend_hash_move_forward_ex(&ce->constants_table, &pos);
  371. }
  372. }
  373. string_printf(str, "%s }\n", indent);
  374. }
  375. /* Static properties */
  376. if (&ce->properties_info) {
  377. /* counting static properties */
  378. count = zend_hash_num_elements(&ce->properties_info);
  379. if (count > 0) {
  380. HashPosition pos;
  381. zend_property_info *prop;
  382. zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
  383. while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
  384. if(prop->flags & ZEND_ACC_SHADOW) {
  385. count_shadow_props++;
  386. } else if (prop->flags & ZEND_ACC_STATIC) {
  387. count_static_props++;
  388. }
  389. zend_hash_move_forward_ex(&ce->properties_info, &pos);
  390. }
  391. }
  392. /* static properties */
  393. string_printf(str, "\n%s - Static properties [%d] {\n", indent, count_static_props);
  394. if (count_static_props > 0) {
  395. HashPosition pos;
  396. zend_property_info *prop;
  397. zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
  398. while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
  399. if ((prop->flags & ZEND_ACC_STATIC) && !(prop->flags & ZEND_ACC_SHADOW)) {
  400. _property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
  401. }
  402. zend_hash_move_forward_ex(&ce->properties_info, &pos);
  403. }
  404. }
  405. string_printf(str, "%s }\n", indent);
  406. }
  407. /* Static methods */
  408. if (&ce->function_table) {
  409. /* counting static methods */
  410. count = zend_hash_num_elements(&ce->function_table);
  411. if (count > 0) {
  412. HashPosition pos;
  413. zend_function *mptr;
  414. zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
  415. while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
  416. if (mptr->common.fn_flags & ZEND_ACC_STATIC
  417. && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
  418. {
  419. count_static_funcs++;
  420. }
  421. zend_hash_move_forward_ex(&ce->function_table, &pos);
  422. }
  423. }
  424. /* static methods */
  425. string_printf(str, "\n%s - Static methods [%d] {", indent, count_static_funcs);
  426. if (count_static_funcs > 0) {
  427. HashPosition pos;
  428. zend_function *mptr;
  429. zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
  430. while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
  431. if (mptr->common.fn_flags & ZEND_ACC_STATIC
  432. && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
  433. {
  434. string_printf(str, "\n");
  435. _function_string(str, mptr, ce, sub_indent.string TSRMLS_CC);
  436. }
  437. zend_hash_move_forward_ex(&ce->function_table, &pos);
  438. }
  439. } else {
  440. string_printf(str, "\n");
  441. }
  442. string_printf(str, "%s }\n", indent);
  443. }
  444. /* Default/Implicit properties */
  445. if (&ce->properties_info) {
  446. count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
  447. string_printf(str, "\n%s - Properties [%d] {\n", indent, count);
  448. if (count > 0) {
  449. HashPosition pos;
  450. zend_property_info *prop;
  451. zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
  452. while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop, &pos) == SUCCESS) {
  453. if (!(prop->flags & (ZEND_ACC_STATIC|ZEND_ACC_SHADOW))) {
  454. _property_string(str, prop, NULL, sub_indent.string TSRMLS_CC);
  455. }
  456. zend_hash_move_forward_ex(&ce->properties_info, &pos);
  457. }
  458. }
  459. string_printf(str, "%s }\n", indent);
  460. }
  461. if (obj && Z_OBJ_HT_P(obj)->get_properties) {
  462. string dyn;
  463. HashTable *properties = Z_OBJ_HT_P(obj)->get_properties(obj TSRMLS_CC);
  464. HashPosition pos;
  465. zval **prop;
  466. string_init(&dyn);
  467. count = 0;
  468. if (properties && zend_hash_num_elements(properties)) {
  469. zend_hash_internal_pointer_reset_ex(properties, &pos);
  470. while (zend_hash_get_current_data_ex(properties, (void **) &prop, &pos) == SUCCESS) {
  471. char *prop_name;
  472. uint prop_name_size;
  473. ulong index;
  474. if (zend_hash_get_current_key_ex(properties, &prop_name, &prop_name_size, &index, 1, &pos) == HASH_KEY_IS_STRING) {
  475. if (prop_name_size && prop_name[0]) { /* skip all private and protected properties */
  476. if (!zend_hash_quick_exists(&ce->properties_info, prop_name, prop_name_size, zend_get_hash_value(prop_name, prop_name_size))) {
  477. count++;
  478. _property_string(&dyn, NULL, prop_name, sub_indent.string TSRMLS_CC);
  479. }
  480. }
  481. efree(prop_name);
  482. }
  483. zend_hash_move_forward_ex(properties, &pos);
  484. }
  485. }
  486. string_printf(str, "\n%s - Dynamic properties [%d] {\n", indent, count);
  487. string_append(str, &dyn);
  488. string_printf(str, "%s }\n", indent);
  489. string_free(&dyn);
  490. }
  491. /* Non static methods */
  492. if (&ce->function_table) {
  493. count = zend_hash_num_elements(&ce->function_table) - count_static_funcs;
  494. if (count > 0) {
  495. HashPosition pos;
  496. zend_function *mptr;
  497. string dyn;
  498. count = 0;
  499. string_init(&dyn);
  500. zend_hash_internal_pointer_reset_ex(&ce->function_table, &pos);
  501. while (zend_hash_get_current_data_ex(&ce->function_table, (void **) &mptr, &pos) == SUCCESS) {
  502. if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0
  503. && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
  504. {
  505. char *key;
  506. uint key_len;
  507. ulong num_index;
  508. uint len = strlen(mptr->common.function_name);
  509. /* Do not display old-style inherited constructors */
  510. if ((mptr->common.fn_flags & ZEND_ACC_CTOR) == 0
  511. || mptr->common.scope == ce
  512. || zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING
  513. || zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0)
  514. {
  515. zend_function *closure;
  516. /* see if this is a closure */
  517. if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
  518. && memcmp(mptr->common.function_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
  519. && (closure = zend_get_closure_invoke_method(obj TSRMLS_CC)) != NULL)
  520. {
  521. mptr = closure;
  522. } else {
  523. closure = NULL;
  524. }
  525. string_printf(&dyn, "\n");
  526. _function_string(&dyn, mptr, ce, sub_indent.string TSRMLS_CC);
  527. count++;
  528. _free_function(closure TSRMLS_CC);
  529. }
  530. }
  531. zend_hash_move_forward_ex(&ce->function_table, &pos);
  532. }
  533. string_printf(str, "\n%s - Methods [%d] {", indent, count);
  534. if (!count) {
  535. string_printf(str, "\n");
  536. }
  537. string_append(str, &dyn);
  538. string_free(&dyn);
  539. } else {
  540. string_printf(str, "\n%s - Methods [0] {\n", indent);
  541. }
  542. string_printf(str, "%s }\n", indent);
  543. }
  544. string_printf(str, "%s}\n", indent);
  545. string_free(&sub_indent);
  546. }
  547. /* }}} */
  548. /* {{{ _const_string */
  549. static void _const_string(string *str, char *name, zval *value, char *indent TSRMLS_DC)
  550. {
  551. char *type;
  552. zval value_copy;
  553. int use_copy;
  554. type = zend_zval_type_name(value);
  555. zend_make_printable_zval(value, &value_copy, &use_copy);
  556. if (use_copy) {
  557. value = &value_copy;
  558. }
  559. string_printf(str, "%s Constant [ %s %s ] { %s }\n",
  560. indent, type, name, Z_STRVAL_P(value));
  561. if (use_copy) {
  562. zval_dtor(value);
  563. }
  564. }
  565. /* }}} */
  566. /* {{{ _get_recv_opcode */
  567. static zend_op* _get_recv_op(zend_op_array *op_array, zend_uint offset)
  568. {
  569. zend_op *op = op_array->opcodes;
  570. zend_op *end = op + op_array->last;
  571. ++offset;
  572. while (op < end) {
  573. if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
  574. && op->op1.u.constant.value.lval == (long)offset)
  575. {
  576. return op;
  577. }
  578. ++op;
  579. }
  580. return NULL;
  581. }
  582. /* }}} */
  583. /* {{{ _parameter_string */
  584. 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)
  585. {
  586. string_printf(str, "Parameter #%d [ ", offset);
  587. if (offset >= required) {
  588. string_printf(str, "<optional> ");
  589. } else {
  590. string_printf(str, "<required> ");
  591. }
  592. if (arg_info->class_name) {
  593. string_printf(str, "%s ", arg_info->class_name);
  594. if (arg_info->allow_null) {
  595. string_printf(str, "or NULL ");
  596. }
  597. } else if (arg_info->array_type_hint) {
  598. string_printf(str, "array ");
  599. if (arg_info->allow_null) {
  600. string_printf(str, "or NULL ");
  601. }
  602. }
  603. if (arg_info->pass_by_reference) {
  604. string_write(str, "&", sizeof("&")-1);
  605. }
  606. if (arg_info->name) {
  607. string_printf(str, "$%s", arg_info->name);
  608. } else {
  609. string_printf(str, "$param%d", offset);
  610. }
  611. if (fptr->type == ZEND_USER_FUNCTION && offset >= required) {
  612. zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset);
  613. if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2.op_type != IS_UNUSED) {
  614. zval *zv, zv_copy;
  615. int use_copy;
  616. string_write(str, " = ", sizeof(" = ")-1);
  617. ALLOC_ZVAL(zv);
  618. *zv = precv->op2.u.constant;
  619. zval_copy_ctor(zv);
  620. INIT_PZVAL(zv);
  621. zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC);
  622. if (Z_TYPE_P(zv) == IS_BOOL) {
  623. if (Z_LVAL_P(zv)) {
  624. string_write(str, "true", sizeof("true")-1);
  625. } else {
  626. string_write(str, "false", sizeof("false")-1);
  627. }
  628. } else if (Z_TYPE_P(zv) == IS_NULL) {
  629. string_write(str, "NULL", sizeof("NULL")-1);
  630. } else if (Z_TYPE_P(zv) == IS_STRING) {
  631. string_write(str, "'", sizeof("'")-1);
  632. string_write(str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 15));
  633. if (Z_STRLEN_P(zv) > 15) {
  634. string_write(str, "...", sizeof("...")-1);
  635. }
  636. string_write(str, "'", sizeof("'")-1);
  637. } else {
  638. zend_make_printable_zval(zv, &zv_copy, &use_copy);
  639. string_write(str, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy));
  640. if (use_copy) {
  641. zval_dtor(&zv_copy);
  642. }
  643. }
  644. zval_ptr_dtor(&zv);
  645. }
  646. }
  647. string_write(str, " ]", sizeof(" ]")-1);
  648. }
  649. /* }}} */
  650. /* {{{ _function_parameter_string */
  651. static void _function_parameter_string(string *str, zend_function *fptr, char* indent TSRMLS_DC)
  652. {
  653. struct _zend_arg_info *arg_info = fptr->common.arg_info;
  654. zend_uint i, required = fptr->common.required_num_args;
  655. if (!arg_info) {
  656. return;
  657. }
  658. string_printf(str, "\n");
  659. string_printf(str, "%s- Parameters [%d] {\n", indent, fptr->common.num_args);
  660. for (i = 0; i < fptr->common.num_args; i++) {
  661. string_printf(str, "%s ", indent);
  662. _parameter_string(str, fptr, arg_info, i, required, indent TSRMLS_CC);
  663. string_write(str, "\n", sizeof("\n")-1);
  664. arg_info++;
  665. }
  666. string_printf(str, "%s}\n", indent);
  667. }
  668. /* }}} */
  669. /* {{{ _function_closure_string */
  670. static void _function_closure_string(string *str, zend_function *fptr, char* indent TSRMLS_DC)
  671. {
  672. zend_uint i, count;
  673. ulong num_index;
  674. char *key;
  675. uint key_len;
  676. HashTable *static_variables;
  677. HashPosition pos;
  678. if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) {
  679. return;
  680. }
  681. static_variables = fptr->op_array.static_variables;
  682. count = zend_hash_num_elements(static_variables);
  683. if (!count) {
  684. return;
  685. }
  686. string_printf(str, "\n");
  687. string_printf(str, "%s- Bound Variables [%d] {\n", indent, zend_hash_num_elements(static_variables));
  688. zend_hash_internal_pointer_reset_ex(static_variables, &pos);
  689. i = 0;
  690. while (i < count) {
  691. zend_hash_get_current_key_ex(static_variables, &key, &key_len, &num_index, 0, &pos);
  692. string_printf(str, "%s Variable #%d [ $%s ]\n", indent, i++, key);
  693. zend_hash_move_forward_ex(static_variables, &pos);
  694. }
  695. string_printf(str, "%s}\n", indent);
  696. }
  697. /* }}} */
  698. /* {{{ _function_string */
  699. static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char* indent TSRMLS_DC)
  700. {
  701. string param_indent;
  702. zend_function *overwrites;
  703. char *lc_name;
  704. unsigned int lc_name_len;
  705. /* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
  706. * What's "wrong" is that any whitespace before the doc comment start is
  707. * swallowed, leading to an unaligned comment.
  708. */
  709. if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
  710. string_printf(str, "%s%s\n", indent, fptr->op_array.doc_comment);
  711. }
  712. string_write(str, indent, strlen(indent));
  713. string_printf(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ "));
  714. string_printf(str, (fptr->type == ZEND_USER_FUNCTION) ? "<user" : "<internal");
  715. if (fptr->common.fn_flags & ZEND_ACC_DEPRECATED) {
  716. string_printf(str, ", deprecated");
  717. }
  718. if (fptr->type == ZEND_INTERNAL_FUNCTION && ((zend_internal_function*)fptr)->module) {
  719. string_printf(str, ":%s", ((zend_internal_function*)fptr)->module->name);
  720. }
  721. if (scope && fptr->common.scope) {
  722. if (fptr->common.scope != scope) {
  723. string_printf(str, ", inherits %s", fptr->common.scope->name);
  724. } else if (fptr->common.scope->parent) {
  725. lc_name_len = strlen(fptr->common.function_name);
  726. lc_name = zend_str_tolower_dup(fptr->common.function_name, lc_name_len);
  727. if (zend_hash_find(&fptr->common.scope->parent->function_table, lc_name, lc_name_len + 1, (void**) &overwrites) == SUCCESS) {
  728. if (fptr->common.scope != overwrites->common.scope) {
  729. string_printf(str, ", overwrites %s", overwrites->common.scope->name);
  730. }
  731. }
  732. efree(lc_name);
  733. }
  734. }
  735. if (fptr->common.prototype && fptr->common.prototype->common.scope) {
  736. string_printf(str, ", prototype %s", fptr->common.prototype->common.scope->name);
  737. }
  738. if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
  739. string_printf(str, ", ctor");
  740. }
  741. if (fptr->common.fn_flags & ZEND_ACC_DTOR) {
  742. string_printf(str, ", dtor");
  743. }
  744. string_printf(str, "> ");
  745. if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
  746. string_printf(str, "abstract ");
  747. }
  748. if (fptr->common.fn_flags & ZEND_ACC_FINAL) {
  749. string_printf(str, "final ");
  750. }
  751. if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
  752. string_printf(str, "static ");
  753. }
  754. if (fptr->common.scope) {
  755. /* These are mutually exclusive */
  756. switch (fptr->common.fn_flags & ZEND_ACC_PPP_MASK) {
  757. case ZEND_ACC_PUBLIC:
  758. string_printf(str, "public ");
  759. break;
  760. case ZEND_ACC_PRIVATE:
  761. string_printf(str, "private ");
  762. break;
  763. case ZEND_ACC_PROTECTED:
  764. string_printf(str, "protected ");
  765. break;
  766. default:
  767. string_printf(str, "<visibility error> ");
  768. break;
  769. }
  770. string_printf(str, "method ");
  771. } else {
  772. string_printf(str, "function ");
  773. }
  774. if (fptr->op_array.return_reference) {
  775. string_printf(str, "&");
  776. }
  777. string_printf(str, "%s ] {\n", fptr->common.function_name);
  778. /* The information where a function is declared is only available for user classes */
  779. if (fptr->type == ZEND_USER_FUNCTION) {
  780. string_printf(str, "%s @@ %s %d - %d\n", indent,
  781. fptr->op_array.filename,
  782. fptr->op_array.line_start,
  783. fptr->op_array.line_end);
  784. }
  785. string_init(&param_indent);
  786. string_printf(&param_indent, "%s ", indent);
  787. if (fptr->common.fn_flags & ZEND_ACC_CLOSURE) {
  788. _function_closure_string(str, fptr, param_indent.string TSRMLS_CC);
  789. }
  790. _function_parameter_string(str, fptr, param_indent.string TSRMLS_CC);
  791. string_free(&param_indent);
  792. string_printf(str, "%s}\n", indent);
  793. }
  794. /* }}} */
  795. /* {{{ _property_string */
  796. static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent TSRMLS_DC)
  797. {
  798. char *class_name;
  799. string_printf(str, "%sProperty [ ", indent);
  800. if (!prop) {
  801. string_printf(str, "<dynamic> public $%s", prop_name);
  802. } else {
  803. if (!(prop->flags & ZEND_ACC_STATIC)) {
  804. if (prop->flags & ZEND_ACC_IMPLICIT_PUBLIC) {
  805. string_write(str, "<implicit> ", sizeof("<implicit> ") - 1);
  806. } else {
  807. string_write(str, "<default> ", sizeof("<default> ") - 1);
  808. }
  809. }
  810. /* These are mutually exclusive */
  811. switch (prop->flags & ZEND_ACC_PPP_MASK) {
  812. case ZEND_ACC_PUBLIC:
  813. string_printf(str, "public ");
  814. break;
  815. case ZEND_ACC_PRIVATE:
  816. string_printf(str, "private ");
  817. break;
  818. case ZEND_ACC_PROTECTED:
  819. string_printf(str, "protected ");
  820. break;
  821. }
  822. if(prop->flags & ZEND_ACC_STATIC) {
  823. string_printf(str, "static ");
  824. }
  825. zend_unmangle_property_name(prop->name, prop->name_length, &class_name, &prop_name);
  826. string_printf(str, "$%s", prop_name);
  827. }
  828. string_printf(str, " ]\n");
  829. }
  830. /* }}} */
  831. static int _extension_ini_string(zend_ini_entry *ini_entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  832. {
  833. string *str = va_arg(args, string *);
  834. char *indent = va_arg(args, char *);
  835. int number = va_arg(args, int);
  836. char *comma = "";
  837. if (number == ini_entry->module_number) {
  838. string_printf(str, " %sEntry [ %s <", indent, ini_entry->name);
  839. if (ini_entry->modifiable == ZEND_INI_ALL) {
  840. string_printf(str, "ALL");
  841. } else {
  842. if (ini_entry->modifiable & ZEND_INI_USER) {
  843. string_printf(str, "USER");
  844. comma = ",";
  845. }
  846. if (ini_entry->modifiable & ZEND_INI_PERDIR) {
  847. string_printf(str, "%sPERDIR", comma);
  848. comma = ",";
  849. }
  850. if (ini_entry->modifiable & ZEND_INI_SYSTEM) {
  851. string_printf(str, "%sSYSTEM", comma);
  852. }
  853. }
  854. string_printf(str, "> ]\n");
  855. string_printf(str, " %s Current = '%s'\n", indent, ini_entry->value ? ini_entry->value : "");
  856. if (ini_entry->modified) {
  857. string_printf(str, " %s Default = '%s'\n", indent, ini_entry->orig_value ? ini_entry->orig_value : "");
  858. }
  859. string_printf(str, " %s}\n", indent);
  860. }
  861. return ZEND_HASH_APPLY_KEEP;
  862. }
  863. static int _extension_class_string(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  864. {
  865. string *str = va_arg(args, string *);
  866. char *indent = va_arg(args, char *);
  867. struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
  868. int *num_classes = va_arg(args, int*);
  869. if ((*pce)->module && !strcasecmp((*pce)->module->name, module->name)) {
  870. string_printf(str, "\n");
  871. _class_string(str, *pce, NULL, indent TSRMLS_CC);
  872. (*num_classes)++;
  873. }
  874. return ZEND_HASH_APPLY_KEEP;
  875. }
  876. static int _extension_const_string(zend_constant *constant TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
  877. {
  878. string *str = va_arg(args, string *);
  879. char *indent = va_arg(args, char *);
  880. struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*);
  881. int *num_classes = va_arg(args, int*);
  882. if (constant->module_number == module->module_number) {
  883. _const_string(str, constant->name, &constant->value, indent TSRMLS_CC);
  884. (*num_classes)++;
  885. }
  886. return ZEND_HASH_APPLY_KEEP;
  887. }
  888. /* {{{ _extension_string */
  889. static void _extension_string(string *str, zend_module_entry *module, char *indent TSRMLS_DC)
  890. {
  891. string_printf(str, "%sExtension [ ", indent);
  892. if (module->type == MODULE_PERSISTENT) {
  893. string_printf(str, "<persistent>");
  894. }
  895. if (module->type == MODULE_TEMPORARY) {
  896. string_printf(str, "<temporary>" );
  897. }
  898. string_printf(str, " extension #%d %s version %s ] {\n",
  899. module->module_number, module->name,
  900. (module->version == NO_VERSION_YET) ? "<no_version>" : module->version);
  901. if (module->deps) {
  902. const zend_module_dep* dep = module->deps;
  903. string_printf(str, "\n - Dependencies {\n");
  904. while(dep->name) {
  905. string_printf(str, "%s Dependency [ %s (", indent, dep->name);
  906. switch(dep->type) {
  907. case MODULE_DEP_REQUIRED:
  908. string_write(str, "Required", sizeof("Required") - 1);
  909. break;
  910. case MODULE_DEP_CONFLICTS:
  911. string_write(str, "Conflicts", sizeof("Conflicts") - 1);
  912. break;
  913. case MODULE_DEP_OPTIONAL:
  914. string_write(str, "Optional", sizeof("Optional") - 1);
  915. break;
  916. default:
  917. string_write(str, "Error", sizeof("Error") - 1); /* shouldn't happen */
  918. break;
  919. }
  920. if (dep->rel) {
  921. string_printf(str, " %s", dep->rel);
  922. }
  923. if (dep->version) {
  924. string_printf(str, " %s", dep->version);
  925. }
  926. string_write(str, ") ]\n", sizeof(") ]\n") - 1);
  927. dep++;
  928. }
  929. string_printf(str, "%s }\n", indent);
  930. }
  931. {
  932. string str_ini;
  933. string_init(&str_ini);
  934. zend_hash_apply_with_arguments(EG(ini_directives) TSRMLS_CC, (apply_func_args_t) _extension_ini_string, 3, &str_ini, indent, module->module_number);
  935. if (str_ini.len > 1) {
  936. string_printf(str, "\n - INI {\n");
  937. string_append(str, &str_ini);
  938. string_printf(str, "%s }\n", indent);
  939. }
  940. string_free(&str_ini);
  941. }
  942. {
  943. string str_constants;
  944. int num_constants = 0;
  945. string_init(&str_constants);
  946. zend_hash_apply_with_arguments(EG(zend_constants) TSRMLS_CC, (apply_func_args_t) _extension_const_string, 4, &str_constants, indent, module, &num_constants);
  947. if (num_constants) {
  948. string_printf(str, "\n - Constants [%d] {\n", num_constants);
  949. string_append(str, &str_constants);
  950. string_printf(str, "%s }\n", indent);
  951. }
  952. string_free(&str_constants);
  953. }
  954. if (module->functions && module->functions->fname) {
  955. zend_function *fptr;
  956. const zend_function_entry *func = module->functions;
  957. string_printf(str, "\n - Functions {\n");
  958. /* Is there a better way of doing this? */
  959. while (func->fname) {
  960. if (zend_hash_find(EG(function_table), func->fname, strlen(func->fname) + 1, (void**) &fptr) == FAILURE) {
  961. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal error: Cannot find extension function %s in global function table", func->fname);
  962. func++;
  963. continue;
  964. }
  965. _function_string(str, fptr, NULL, " " TSRMLS_CC);
  966. func++;
  967. }
  968. string_printf(str, "%s }\n", indent);
  969. }
  970. {
  971. string str_classes;
  972. string sub_indent;
  973. int num_classes = 0;
  974. string_init(&sub_indent);
  975. string_printf(&sub_indent, "%s ", indent);
  976. string_init(&str_classes);
  977. 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);
  978. if (num_classes) {
  979. string_printf(str, "\n - Classes [%d] {", num_classes);
  980. string_append(str, &str_classes);
  981. string_printf(str, "%s }\n", indent);
  982. }
  983. string_free(&str_classes);
  984. string_free(&sub_indent);
  985. }
  986. string_printf(str, "%s}\n", indent);
  987. }
  988. /* }}} */
  989. /* {{{ _function_check_flag */
  990. static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
  991. {
  992. reflection_object *intern;
  993. zend_function *mptr;
  994. if (zend_parse_parameters_none() == FAILURE) {
  995. return;
  996. }
  997. GET_REFLECTION_OBJECT_PTR(mptr);
  998. RETURN_BOOL(mptr->common.fn_flags & mask);
  999. }
  1000. /* }}} */
  1001. /* {{{ zend_reflection_class_factory */
  1002. PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_DC)
  1003. {
  1004. reflection_object *intern;
  1005. zval *name;
  1006. MAKE_STD_ZVAL(name);
  1007. ZVAL_STRINGL(name, ce->name, ce->name_length, 1);
  1008. reflection_instantiate(reflection_class_ptr, object TSRMLS_CC);
  1009. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1010. intern->ptr = ce;
  1011. intern->ref_type = REF_TYPE_OTHER;
  1012. intern->ce = ce;
  1013. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1014. }
  1015. /* }}} */
  1016. /* {{{ reflection_extension_factory */
  1017. static void reflection_extension_factory(zval *object, const char *name_str TSRMLS_DC)
  1018. {
  1019. reflection_object *intern;
  1020. zval *name;
  1021. int name_len = strlen(name_str);
  1022. char *lcname;
  1023. struct _zend_module_entry *module;
  1024. ALLOCA_FLAG(use_heap)
  1025. lcname = do_alloca(name_len + 1, use_heap);
  1026. zend_str_tolower_copy(lcname, name_str, name_len);
  1027. if (zend_hash_find(&module_registry, lcname, name_len + 1, (void **)&module) == FAILURE) {
  1028. free_alloca(lcname, use_heap);
  1029. return;
  1030. }
  1031. free_alloca(lcname, use_heap);
  1032. reflection_instantiate(reflection_extension_ptr, object TSRMLS_CC);
  1033. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1034. MAKE_STD_ZVAL(name);
  1035. ZVAL_STRINGL(name, module->name, name_len, 1);
  1036. intern->ptr = module;
  1037. intern->ref_type = REF_TYPE_OTHER;
  1038. intern->ce = NULL;
  1039. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1040. }
  1041. /* }}} */
  1042. /* {{{ reflection_parameter_factory */
  1043. static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, zval *object TSRMLS_DC)
  1044. {
  1045. reflection_object *intern;
  1046. parameter_reference *reference;
  1047. zval *name;
  1048. if (closure_object) {
  1049. Z_ADDREF_P(closure_object);
  1050. }
  1051. MAKE_STD_ZVAL(name);
  1052. if (arg_info->name) {
  1053. ZVAL_STRINGL(name, arg_info->name, arg_info->name_len, 1);
  1054. } else {
  1055. ZVAL_NULL(name);
  1056. }
  1057. reflection_instantiate(reflection_parameter_ptr, object TSRMLS_CC);
  1058. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1059. reference = (parameter_reference*) emalloc(sizeof(parameter_reference));
  1060. reference->arg_info = arg_info;
  1061. reference->offset = offset;
  1062. reference->required = required;
  1063. reference->fptr = fptr;
  1064. intern->ptr = reference;
  1065. intern->ref_type = REF_TYPE_PARAMETER;
  1066. intern->ce = fptr->common.scope;
  1067. intern->obj = closure_object;
  1068. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1069. }
  1070. /* }}} */
  1071. /* {{{ reflection_function_factory */
  1072. static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object TSRMLS_DC)
  1073. {
  1074. reflection_object *intern;
  1075. zval *name;
  1076. if (closure_object) {
  1077. Z_ADDREF_P(closure_object);
  1078. }
  1079. MAKE_STD_ZVAL(name);
  1080. ZVAL_STRING(name, function->common.function_name, 1);
  1081. reflection_instantiate(reflection_function_ptr, object TSRMLS_CC);
  1082. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1083. intern->ptr = function;
  1084. intern->ref_type = REF_TYPE_FUNCTION;
  1085. intern->ce = NULL;
  1086. intern->obj = closure_object;
  1087. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1088. }
  1089. /* }}} */
  1090. /* {{{ reflection_method_factory */
  1091. static void reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object TSRMLS_DC)
  1092. {
  1093. reflection_object *intern;
  1094. zval *name;
  1095. zval *classname;
  1096. if (closure_object) {
  1097. Z_ADDREF_P(closure_object);
  1098. }
  1099. MAKE_STD_ZVAL(name);
  1100. MAKE_STD_ZVAL(classname);
  1101. ZVAL_STRING(name, method->common.function_name, 1);
  1102. ZVAL_STRINGL(classname, method->common.scope->name, method->common.scope->name_length, 1);
  1103. reflection_instantiate(reflection_method_ptr, object TSRMLS_CC);
  1104. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1105. intern->ptr = method;
  1106. intern->ref_type = REF_TYPE_FUNCTION;
  1107. intern->ce = ce;
  1108. intern->obj = closure_object;
  1109. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1110. zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
  1111. }
  1112. /* }}} */
  1113. /* {{{ reflection_property_factory */
  1114. static void reflection_property_factory(zend_class_entry *ce, zend_property_info *prop, zval *object TSRMLS_DC)
  1115. {
  1116. reflection_object *intern;
  1117. zval *name;
  1118. zval *classname;
  1119. property_reference *reference;
  1120. char *class_name, *prop_name;
  1121. zend_unmangle_property_name(prop->name, prop->name_length, &class_name, &prop_name);
  1122. if (!(prop->flags & ZEND_ACC_PRIVATE)) {
  1123. /* we have to search the class hierarchy for this (implicit) public or protected property */
  1124. zend_class_entry *tmp_ce = ce, *store_ce = ce;
  1125. zend_property_info *tmp_info = NULL;
  1126. while (tmp_ce && zend_hash_find(&tmp_ce->properties_info, prop_name, strlen(prop_name) + 1, (void **) &tmp_info) != SUCCESS) {
  1127. ce = tmp_ce;
  1128. tmp_ce = tmp_ce->parent;
  1129. }
  1130. if (tmp_info && !(tmp_info->flags & ZEND_ACC_SHADOW)) { /* found something and it's not a parent's private */
  1131. prop = tmp_info;
  1132. } else { /* not found, use initial value */
  1133. ce = store_ce;
  1134. }
  1135. }
  1136. MAKE_STD_ZVAL(name);
  1137. MAKE_STD_ZVAL(classname);
  1138. ZVAL_STRING(name, prop_name, 1);
  1139. ZVAL_STRINGL(classname, prop->ce->name, prop->ce->name_length, 1);
  1140. reflection_instantiate(reflection_property_ptr, object TSRMLS_CC);
  1141. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1142. reference = (property_reference*) emalloc(sizeof(property_reference));
  1143. reference->ce = ce;
  1144. reference->prop = *prop;
  1145. intern->ptr = reference;
  1146. intern->ref_type = REF_TYPE_PROPERTY;
  1147. intern->ce = ce;
  1148. intern->ignore_visibility = 0;
  1149. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1150. zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL);
  1151. }
  1152. /* }}} */
  1153. /* {{{ _reflection_export */
  1154. static void _reflection_export(INTERNAL_FUNCTION_PARAMETERS, zend_class_entry *ce_ptr, int ctor_argc)
  1155. {
  1156. zval *reflector_ptr;
  1157. zval output, *output_ptr = &output;
  1158. zval *argument_ptr, *argument2_ptr;
  1159. zval *retval_ptr, **params[2];
  1160. int result;
  1161. int return_output = 0;
  1162. zend_fcall_info fci;
  1163. zend_fcall_info_cache fcc;
  1164. zval fname;
  1165. if (ctor_argc == 1) {
  1166. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|b", &argument_ptr, &return_output) == FAILURE) {
  1167. return;
  1168. }
  1169. } else {
  1170. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|b", &argument_ptr, &argument2_ptr, &return_output) == FAILURE) {
  1171. return;
  1172. }
  1173. }
  1174. INIT_PZVAL(&output);
  1175. /* Create object */
  1176. MAKE_STD_ZVAL(reflector_ptr);
  1177. if (object_and_properties_init(reflector_ptr, ce_ptr, NULL) == FAILURE) {
  1178. _DO_THROW("Could not create reflector");
  1179. }
  1180. /* Call __construct() */
  1181. params[0] = &argument_ptr;
  1182. params[1] = &argument2_ptr;
  1183. fci.size = sizeof(fci);
  1184. fci.function_table = NULL;
  1185. fci.function_name = NULL;
  1186. fci.symbol_table = NULL;
  1187. fci.object_ptr = reflector_ptr;
  1188. fci.retval_ptr_ptr = &retval_ptr;
  1189. fci.param_count = ctor_argc;
  1190. fci.params = params;
  1191. fci.no_separation = 1;
  1192. fcc.initialized = 1;
  1193. fcc.function_handler = ce_ptr->constructor;
  1194. fcc.calling_scope = ce_ptr;
  1195. fcc.called_scope = Z_OBJCE_P(reflector_ptr);
  1196. fcc.object_ptr = reflector_ptr;
  1197. result = zend_call_function(&fci, &fcc TSRMLS_CC);
  1198. if (retval_ptr) {
  1199. zval_ptr_dtor(&retval_ptr);
  1200. }
  1201. if (EG(exception)) {
  1202. zval_ptr_dtor(&reflector_ptr);
  1203. return;
  1204. }
  1205. if (result == FAILURE) {
  1206. zval_ptr_dtor(&reflector_ptr);
  1207. _DO_THROW("Could not create reflector");
  1208. }
  1209. /* Call static reflection::export */
  1210. ZVAL_BOOL(&output, return_output);
  1211. params[0] = &reflector_ptr;
  1212. params[1] = &output_ptr;
  1213. ZVAL_STRINGL(&fname, "reflection::export", sizeof("reflection::export") - 1, 0);
  1214. fci.function_table = &reflection_ptr->function_table;
  1215. fci.function_name = &fname;
  1216. fci.object_ptr = NULL;
  1217. fci.retval_ptr_ptr = &retval_ptr;
  1218. fci.param_count = 2;
  1219. fci.params = params;
  1220. fci.no_separation = 1;
  1221. result = zend_call_function(&fci, NULL TSRMLS_CC);
  1222. if (result == FAILURE && EG(exception) == NULL) {
  1223. zval_ptr_dtor(&reflector_ptr);
  1224. zval_ptr_dtor(&retval_ptr);
  1225. _DO_THROW("Could not execute reflection::export()");
  1226. }
  1227. if (return_output) {
  1228. COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
  1229. } else {
  1230. zval_ptr_dtor(&retval_ptr);
  1231. }
  1232. /* Destruct reflector which is no longer needed */
  1233. zval_ptr_dtor(&reflector_ptr);
  1234. }
  1235. /* }}} */
  1236. /* {{{ Preventing __clone from being called */
  1237. ZEND_METHOD(reflection, __clone)
  1238. {
  1239. /* Should never be executable */
  1240. _DO_THROW("Cannot clone object using __clone()");
  1241. }
  1242. /* }}} */
  1243. /* {{{ proto public static mixed Reflection::export(Reflector r [, bool return])
  1244. Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
  1245. ZEND_METHOD(reflection, export)
  1246. {
  1247. zval *object, fname, *retval_ptr;
  1248. int result;
  1249. zend_bool return_output = 0;
  1250. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|b", &object, reflector_ptr, &return_output) == FAILURE) {
  1251. return;
  1252. }
  1253. /* Invoke the __toString() method */
  1254. ZVAL_STRINGL(&fname, "__tostring", sizeof("__tostring") - 1, 1);
  1255. result= call_user_function_ex(NULL, &object, &fname, &retval_ptr, 0, NULL, 0, NULL TSRMLS_CC);
  1256. zval_dtor(&fname);
  1257. if (result == FAILURE) {
  1258. _DO_THROW("Invocation of method __toString() failed");
  1259. /* Returns from this function */
  1260. }
  1261. if (!retval_ptr) {
  1262. php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s::__toString() did not return anything", Z_OBJCE_P(object)->name);
  1263. RETURN_FALSE;
  1264. }
  1265. if (return_output) {
  1266. COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
  1267. } else {
  1268. /* No need for _r variant, return of __toString should always be a string */
  1269. zend_print_zval(retval_ptr, 0);
  1270. zend_printf("\n");
  1271. zval_ptr_dtor(&retval_ptr);
  1272. }
  1273. }
  1274. /* }}} */
  1275. /* {{{ proto public static array Reflection::getModifierNames(int modifiers)
  1276. Returns an array of modifier names */
  1277. ZEND_METHOD(reflection, getModifierNames)
  1278. {
  1279. long modifiers;
  1280. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &modifiers) == FAILURE) {
  1281. return;
  1282. }
  1283. array_init(return_value);
  1284. if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
  1285. add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1, 1);
  1286. }
  1287. if (modifiers & (ZEND_ACC_FINAL | ZEND_ACC_FINAL_CLASS)) {
  1288. add_next_index_stringl(return_value, "final", sizeof("final")-1, 1);
  1289. }
  1290. if (modifiers & ZEND_ACC_IMPLICIT_PUBLIC) {
  1291. add_next_index_stringl(return_value, "public", sizeof("public")-1, 1);
  1292. }
  1293. /* These are mutually exclusive */
  1294. switch (modifiers & ZEND_ACC_PPP_MASK) {
  1295. case ZEND_ACC_PUBLIC:
  1296. add_next_index_stringl(return_value, "public", sizeof("public")-1, 1);
  1297. break;
  1298. case ZEND_ACC_PRIVATE:
  1299. add_next_index_stringl(return_value, "private", sizeof("private")-1, 1);
  1300. break;
  1301. case ZEND_ACC_PROTECTED:
  1302. add_next_index_stringl(return_value, "protected", sizeof("protected")-1, 1);
  1303. break;
  1304. }
  1305. if (modifiers & ZEND_ACC_STATIC) {
  1306. add_next_index_stringl(return_value, "static", sizeof("static")-1, 1);
  1307. }
  1308. }
  1309. /* }}} */
  1310. /* {{{ proto public static mixed ReflectionFunction::export(string name [, bool return])
  1311. Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
  1312. ZEND_METHOD(reflection_function, export)
  1313. {
  1314. _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_function_ptr, 1);
  1315. }
  1316. /* }}} */
  1317. /* {{{ proto public void ReflectionFunction::__construct(string name)
  1318. Constructor. Throws an Exception in case the given function does not exist */
  1319. ZEND_METHOD(reflection_function, __construct)
  1320. {
  1321. zval *name;
  1322. zval *object;
  1323. zval *closure = NULL;
  1324. char *lcname;
  1325. reflection_object *intern;
  1326. zend_function *fptr;
  1327. char *name_str;
  1328. int name_len;
  1329. object = getThis();
  1330. intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
  1331. if (intern == NULL) {
  1332. return;
  1333. }
  1334. if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "O", &closure, zend_ce_closure) == SUCCESS) {
  1335. fptr = (zend_function*)zend_get_closure_method_def(closure TSRMLS_CC);
  1336. Z_ADDREF_P(closure);
  1337. } else if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == SUCCESS) {
  1338. char *nsname;
  1339. lcname = zend_str_tolower_dup(name_str, name_len);
  1340. /* Ignore leading "\" */
  1341. nsname = lcname;
  1342. if (lcname[0] == '\\') {
  1343. nsname = &lcname[1];
  1344. name_len--;
  1345. }
  1346. if (zend_hash_find(EG(function_table), nsname, name_len + 1, (void **)&fptr) == FAILURE) {
  1347. efree(lcname);
  1348. zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
  1349. "Function %s() does not exist", name_str);
  1350. return;
  1351. }
  1352. efree(lcname);
  1353. } else {
  1354. return;
  1355. }
  1356. MAKE_STD_ZVAL(name);
  1357. ZVAL_STRING(name, fptr->common.function_name, 1);
  1358. zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
  1359. intern->ptr = fptr;
  1360. intern->ref_type = REF_TYPE_FUNCTION;
  1361. intern->obj = closure;
  1362. intern->ce = NULL;
  1363. }
  1364. /* }}} */
  1365. /* {{{ proto public string ReflectionFunction::__toString()
  1366. Returns a string representation */
  1367. ZEND_METHOD(reflection_function, __toString)
  1368. {
  1369. reflection_object *intern;
  1370. zend_function *fptr;
  1371. string str;
  1372. if (zend_parse_parameters_none() == FAILURE) {
  1373. return;
  1374. }
  1375. GET_REFLECTION_OBJECT_PTR(fptr);
  1376. string_init(&str);
  1377. _function_string(&str, fptr, intern->ce, "" TSRMLS_CC);
  1378. RETURN_STRINGL(str.string, str.len - 1, 0);
  1379. }
  1380. /* }}} */
  1381. /* {{{ proto public string ReflectionFunction::getName()
  1382. Returns this function's name */
  1383. ZEND_METHOD(reflection_function, getName)
  1384. {
  1385. if (zend_parse_parameters_none() == FAILURE) {
  1386. return;
  1387. }
  1388. _default_get_entry(getThis(), "name", sizeof("name"), return_value TSRMLS_CC);
  1389. }
  1390. /* }}} */
  1391. /* {{{ proto public bool ReflectionFunction::isClosure()
  1392. Returns whether this is a closure */
  1393. ZEND_METHOD(reflection_function, isClosure)
  1394. {
  1395. reflection_object *intern;
  1396. zend_function *fptr;
  1397. if (

Large files files are truncated, but you can click here to view the full file