You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

622 lines
22 KiB

11 years ago
11 years ago
11 years ago
13 years ago
10 years ago
10 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
18 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2015 Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend 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.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Christian Seiler <chris_se@gmx.net> |
  16. | Dmitry Stogov <dmitry@zend.com> |
  17. | Marcus Boerger <helly@php.net> |
  18. +----------------------------------------------------------------------+
  19. */
  20. /* $Id$ */
  21. #include "zend.h"
  22. #include "zend_API.h"
  23. #include "zend_closures.h"
  24. #include "zend_exceptions.h"
  25. #include "zend_interfaces.h"
  26. #include "zend_objects.h"
  27. #include "zend_objects_API.h"
  28. #include "zend_globals.h"
  29. #define ZEND_CLOSURE_PRINT_NAME "Closure object"
  30. #define ZEND_CLOSURE_PROPERTY_ERROR() \
  31. zend_throw_error(NULL, "Closure object cannot have properties")
  32. typedef struct _zend_closure {
  33. zend_object std;
  34. zend_function func;
  35. zval this_ptr;
  36. zend_class_entry *called_scope;
  37. void (*orig_internal_handler)(INTERNAL_FUNCTION_PARAMETERS);
  38. } zend_closure;
  39. /* non-static since it needs to be referenced */
  40. ZEND_API zend_class_entry *zend_ce_closure;
  41. static zend_object_handlers closure_handlers;
  42. ZEND_METHOD(Closure, __invoke) /* {{{ */
  43. {
  44. zend_function *func = EX(func);
  45. zval *arguments;
  46. arguments = emalloc(sizeof(zval) * ZEND_NUM_ARGS());
  47. if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
  48. efree(arguments);
  49. zend_throw_error(NULL, "Cannot get arguments for calling closure");
  50. RETVAL_FALSE;
  51. } else if (call_user_function_ex(CG(function_table), NULL, getThis(), return_value, ZEND_NUM_ARGS(), arguments, 1, NULL) == FAILURE) {
  52. RETVAL_FALSE;
  53. }
  54. efree(arguments);
  55. /* destruct the function also, then - we have allocated it in get_method */
  56. zend_string_release(func->internal_function.function_name);
  57. efree(func);
  58. #if ZEND_DEBUG
  59. execute_data->func = NULL;
  60. #endif
  61. }
  62. /* }}} */
  63. /* {{{ proto mixed Closure::call(object to [, mixed parameter] [, mixed ...] )
  64. Call closure, binding to a given object with its class as the scope */
  65. ZEND_METHOD(Closure, call)
  66. {
  67. zval *zclosure, *newthis, closure_result;
  68. zend_closure *closure;
  69. zend_fcall_info fci;
  70. zend_fcall_info_cache fci_cache;
  71. zval *my_params;
  72. int my_param_count = 0;
  73. zend_function my_function;
  74. zend_object *newobj;
  75. if (zend_parse_parameters(ZEND_NUM_ARGS(), "o*", &newthis, &my_params, &my_param_count) == FAILURE) {
  76. return;
  77. }
  78. zclosure = getThis();
  79. closure = (zend_closure *) Z_OBJ_P(zclosure);
  80. if (closure->func.common.fn_flags & ZEND_ACC_STATIC) {
  81. zend_error(E_WARNING, "Cannot bind an instance to a static closure");
  82. return;
  83. }
  84. if (closure->func.type == ZEND_INTERNAL_FUNCTION) {
  85. /* verify that we aren't binding internal function to a wrong object */
  86. if ((closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0 &&
  87. closure->func.common.scope &&
  88. !instanceof_function(Z_OBJCE_P(newthis), closure->func.common.scope)) {
  89. zend_error(E_WARNING, "Cannot bind function %s::%s to object of class %s", ZSTR_VAL(closure->func.common.scope->name), ZSTR_VAL(closure->func.common.function_name), ZSTR_VAL(Z_OBJCE_P(newthis)->name));
  90. return;
  91. }
  92. }
  93. newobj = Z_OBJ_P(newthis);
  94. if (newobj->ce != closure->func.common.scope && newobj->ce->type == ZEND_INTERNAL_CLASS) {
  95. /* rebinding to internal class is not allowed */
  96. zend_error(E_WARNING, "Cannot bind closure to object of internal class %s", ZSTR_VAL(newobj->ce->name));
  97. return;
  98. }
  99. /* This should never happen as closures will always be callable */
  100. if (zend_fcall_info_init(zclosure, 0, &fci, &fci_cache, NULL, NULL) != SUCCESS) {
  101. ZEND_ASSERT(0);
  102. }
  103. fci.retval = &closure_result;
  104. fci.params = my_params;
  105. fci.param_count = my_param_count;
  106. fci.object = fci_cache.object = newobj;
  107. fci_cache.initialized = 1;
  108. if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
  109. zval new_closure;
  110. zend_create_closure(&new_closure, fci_cache.function_handler, Z_OBJCE_P(newthis), closure->called_scope, newthis);
  111. closure = (zend_closure *) Z_OBJ(new_closure);
  112. fci_cache.function_handler = &closure->func;
  113. } else {
  114. memcpy(&my_function, fci_cache.function_handler, fci_cache.function_handler->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
  115. /* use scope of passed object */
  116. my_function.common.scope = Z_OBJCE_P(newthis);
  117. fci_cache.function_handler = &my_function;
  118. /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
  119. if (ZEND_USER_CODE(my_function.type) && closure->func.common.scope != Z_OBJCE_P(newthis)) {
  120. my_function.op_array.run_time_cache = emalloc(my_function.op_array.cache_size);
  121. memset(my_function.op_array.run_time_cache, 0, my_function.op_array.cache_size);
  122. }
  123. }
  124. if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(closure_result) != IS_UNDEF) {
  125. ZVAL_COPY_VALUE(return_value, &closure_result);
  126. }
  127. if (fci_cache.function_handler->common.fn_flags & ZEND_ACC_GENERATOR) {
  128. /* copied upon generator creation */
  129. --GC_REFCOUNT(&closure->std);
  130. } else if (ZEND_USER_CODE(my_function.type) && closure->func.common.scope != Z_OBJCE_P(newthis)) {
  131. efree(my_function.op_array.run_time_cache);
  132. }
  133. }
  134. /* }}} */
  135. /* {{{ proto Closure Closure::bind(callable old, object to [, mixed scope])
  136. Create a closure from another one and bind to another object and scope */
  137. ZEND_METHOD(Closure, bind)
  138. {
  139. zval *newthis, *zclosure, *scope_arg = NULL;
  140. zend_closure *closure, *new_closure;
  141. zend_class_entry *ce, *called_scope;
  142. if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
  143. RETURN_NULL();
  144. }
  145. closure = (zend_closure *)Z_OBJ_P(zclosure);
  146. if ((newthis != NULL) && (closure->func.common.fn_flags & ZEND_ACC_STATIC)) {
  147. zend_error(E_WARNING, "Cannot bind an instance to a static closure");
  148. }
  149. if (newthis == NULL && !(closure->func.common.fn_flags & ZEND_ACC_STATIC)
  150. && closure->func.common.scope && closure->func.type == ZEND_INTERNAL_FUNCTION) {
  151. zend_error(E_WARNING, "Cannot unbind $this of internal method");
  152. return;
  153. }
  154. if (scope_arg != NULL) { /* scope argument was given */
  155. if (Z_TYPE_P(scope_arg) == IS_OBJECT) {
  156. ce = Z_OBJCE_P(scope_arg);
  157. } else if (Z_TYPE_P(scope_arg) == IS_NULL) {
  158. ce = NULL;
  159. } else {
  160. zend_string *class_name = zval_get_string(scope_arg);
  161. if (zend_string_equals_literal(class_name, "static")) {
  162. ce = closure->func.common.scope;
  163. } else if ((ce = zend_lookup_class_ex(class_name, NULL, 1)) == NULL) {
  164. zend_error(E_WARNING, "Class '%s' not found", ZSTR_VAL(class_name));
  165. zend_string_release(class_name);
  166. RETURN_NULL();
  167. }
  168. zend_string_release(class_name);
  169. }
  170. if(ce && ce != closure->func.common.scope && ce->type == ZEND_INTERNAL_CLASS) {
  171. /* rebinding to internal class is not allowed */
  172. zend_error(E_WARNING, "Cannot bind closure to scope of internal class %s", ZSTR_VAL(ce->name));
  173. return;
  174. }
  175. } else { /* scope argument not given; do not change the scope by default */
  176. ce = closure->func.common.scope;
  177. }
  178. if (newthis) {
  179. called_scope = Z_OBJCE_P(newthis);
  180. } else {
  181. called_scope = ce;
  182. }
  183. zend_create_closure(return_value, &closure->func, ce, called_scope, newthis);
  184. new_closure = (zend_closure *) Z_OBJ_P(return_value);
  185. /* Runtime cache relies on bound scope to be immutable, hence we need a separate rt cache in case scope changed */
  186. if (ZEND_USER_CODE(closure->func.type) && (closure->func.common.scope != new_closure->func.common.scope || (closure->func.op_array.fn_flags & ZEND_ACC_NO_RT_ARENA))) {
  187. new_closure->func.op_array.run_time_cache = emalloc(new_closure->func.op_array.cache_size);
  188. memset(new_closure->func.op_array.run_time_cache, 0, new_closure->func.op_array.cache_size);
  189. new_closure->func.op_array.fn_flags |= ZEND_ACC_NO_RT_ARENA;
  190. }
  191. }
  192. /* }}} */
  193. static ZEND_COLD zend_function *zend_closure_get_constructor(zend_object *object) /* {{{ */
  194. {
  195. zend_throw_error(NULL, "Instantiation of 'Closure' is not allowed");
  196. return NULL;
  197. }
  198. /* }}} */
  199. static int zend_closure_compare_objects(zval *o1, zval *o2) /* {{{ */
  200. {
  201. return (Z_OBJ_P(o1) != Z_OBJ_P(o2));
  202. }
  203. /* }}} */
  204. ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* {{{ */
  205. {
  206. zend_closure *closure = (zend_closure *)object;
  207. zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
  208. const uint32_t keep_flags =
  209. ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_VARIADIC | ZEND_ACC_HAS_RETURN_TYPE;
  210. invoke->common = closure->func.common;
  211. /* We return ZEND_INTERNAL_FUNCTION, but arg_info representation is the
  212. * same as for ZEND_USER_FUNCTION (uses zend_string* instead of char*).
  213. * This is not a problem, because ZEND_ACC_HAS_TYPE_HINTS is never set,
  214. * and we won't check arguments on internal function. We also set
  215. * ZEND_ACC_USER_ARG_INFO flag to prevent invalid usage by Reflection */
  216. invoke->type = ZEND_INTERNAL_FUNCTION;
  217. invoke->internal_function.fn_flags =
  218. ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & keep_flags);
  219. if (closure->func.type != ZEND_INTERNAL_FUNCTION || (closure->func.common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
  220. invoke->internal_function.fn_flags |=
  221. ZEND_ACC_USER_ARG_INFO;
  222. }
  223. invoke->internal_function.handler = ZEND_MN(Closure___invoke);
  224. invoke->internal_function.module = 0;
  225. invoke->internal_function.scope = zend_ce_closure;
  226. invoke->internal_function.function_name = zend_string_init(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1, 0);
  227. return invoke;
  228. }
  229. /* }}} */
  230. ZEND_API const zend_function *zend_get_closure_method_def(zval *obj) /* {{{ */
  231. {
  232. zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
  233. return &closure->func;
  234. }
  235. /* }}} */
  236. ZEND_API zval* zend_get_closure_this_ptr(zval *obj) /* {{{ */
  237. {
  238. zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
  239. return &closure->this_ptr;
  240. }
  241. /* }}} */
  242. static zend_function *zend_closure_get_method(zend_object **object, zend_string *method, const zval *key) /* {{{ */
  243. {
  244. zend_string *lc_name;
  245. lc_name = zend_string_tolower(method);
  246. if (zend_string_equals_literal(method, ZEND_INVOKE_FUNC_NAME)) {
  247. zend_string_release(lc_name);
  248. return zend_get_closure_invoke_method(*object);
  249. }
  250. zend_string_release(lc_name);
  251. return std_object_handlers.get_method(object, method, key);
  252. }
  253. /* }}} */
  254. static zval *zend_closure_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
  255. {
  256. ZEND_CLOSURE_PROPERTY_ERROR();
  257. return &EG(uninitialized_zval);
  258. }
  259. /* }}} */
  260. static void zend_closure_write_property(zval *object, zval *member, zval *value, void **cache_slot) /* {{{ */
  261. {
  262. ZEND_CLOSURE_PROPERTY_ERROR();
  263. }
  264. /* }}} */
  265. static zval *zend_closure_get_property_ptr_ptr(zval *object, zval *member, int type, void **cache_slot) /* {{{ */
  266. {
  267. ZEND_CLOSURE_PROPERTY_ERROR();
  268. return NULL;
  269. }
  270. /* }}} */
  271. static int zend_closure_has_property(zval *object, zval *member, int has_set_exists, void **cache_slot) /* {{{ */
  272. {
  273. if (has_set_exists != 2) {
  274. ZEND_CLOSURE_PROPERTY_ERROR();
  275. }
  276. return 0;
  277. }
  278. /* }}} */
  279. static void zend_closure_unset_property(zval *object, zval *member, void **cache_slot) /* {{{ */
  280. {
  281. ZEND_CLOSURE_PROPERTY_ERROR();
  282. }
  283. /* }}} */
  284. static void zend_closure_free_storage(zend_object *object) /* {{{ */
  285. {
  286. zend_closure *closure = (zend_closure *)object;
  287. zend_object_std_dtor(&closure->std);
  288. if (closure->func.type == ZEND_USER_FUNCTION) {
  289. if (closure->func.op_array.fn_flags & ZEND_ACC_NO_RT_ARENA) {
  290. efree(closure->func.op_array.run_time_cache);
  291. closure->func.op_array.run_time_cache = NULL;
  292. }
  293. destroy_op_array(&closure->func.op_array);
  294. }
  295. if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
  296. zval_ptr_dtor(&closure->this_ptr);
  297. }
  298. }
  299. /* }}} */
  300. static zend_object *zend_closure_new(zend_class_entry *class_type) /* {{{ */
  301. {
  302. zend_closure *closure;
  303. closure = emalloc(sizeof(zend_closure));
  304. memset(closure, 0, sizeof(zend_closure));
  305. zend_object_std_init(&closure->std, class_type);
  306. closure->std.handlers = &closure_handlers;
  307. return (zend_object*)closure;
  308. }
  309. /* }}} */
  310. static zend_object *zend_closure_clone(zval *zobject) /* {{{ */
  311. {
  312. zend_closure *closure = (zend_closure *)Z_OBJ_P(zobject);
  313. zval result;
  314. zend_create_closure(&result, &closure->func,
  315. closure->func.common.scope, closure->called_scope, &closure->this_ptr);
  316. return Z_OBJ(result);
  317. }
  318. /* }}} */
  319. int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr) /* {{{ */
  320. {
  321. zend_closure *closure;
  322. if (Z_TYPE_P(obj) != IS_OBJECT) {
  323. return FAILURE;
  324. }
  325. closure = (zend_closure *)Z_OBJ_P(obj);
  326. *fptr_ptr = &closure->func;
  327. *ce_ptr = closure->called_scope;
  328. if (obj_ptr) {
  329. if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
  330. *obj_ptr = Z_OBJ(closure->this_ptr);
  331. } else {
  332. *obj_ptr = NULL;
  333. }
  334. }
  335. return SUCCESS;
  336. }
  337. /* }}} */
  338. static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{ */
  339. {
  340. zend_closure *closure = (zend_closure *)Z_OBJ_P(object);
  341. zval val;
  342. struct _zend_arg_info *arg_info = closure->func.common.arg_info;
  343. HashTable *debug_info;
  344. *is_temp = 1;
  345. ALLOC_HASHTABLE(debug_info);
  346. zend_hash_init(debug_info, 8, NULL, ZVAL_PTR_DTOR, 0);
  347. if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
  348. HashTable *static_variables = closure->func.op_array.static_variables;
  349. ZVAL_ARR(&val, zend_array_dup(static_variables));
  350. zend_hash_str_update(debug_info, "static", sizeof("static")-1, &val);
  351. }
  352. if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
  353. Z_ADDREF(closure->this_ptr);
  354. zend_hash_str_update(debug_info, "this", sizeof("this")-1, &closure->this_ptr);
  355. }
  356. if (arg_info &&
  357. (closure->func.common.num_args ||
  358. (closure->func.common.fn_flags & ZEND_ACC_VARIADIC))) {
  359. uint32_t i, num_args, required = closure->func.common.required_num_args;
  360. array_init(&val);
  361. num_args = closure->func.common.num_args;
  362. if (closure->func.common.fn_flags & ZEND_ACC_VARIADIC) {
  363. num_args++;
  364. }
  365. for (i = 0; i < num_args; i++) {
  366. zend_string *name;
  367. zval info;
  368. if (arg_info->name) {
  369. name = zend_strpprintf(0, "%s$%s",
  370. arg_info->pass_by_reference ? "&" : "",
  371. ZSTR_VAL(arg_info->name));
  372. } else {
  373. name = zend_strpprintf(0, "%s$param%d",
  374. arg_info->pass_by_reference ? "&" : "",
  375. i + 1);
  376. }
  377. ZVAL_NEW_STR(&info, zend_strpprintf(0, "%s", i >= required ? "<optional>" : "<required>"));
  378. zend_hash_update(Z_ARRVAL(val), name, &info);
  379. zend_string_release(name);
  380. arg_info++;
  381. }
  382. zend_hash_str_update(debug_info, "parameter", sizeof("parameter")-1, &val);
  383. }
  384. return debug_info;
  385. }
  386. /* }}} */
  387. static HashTable *zend_closure_get_gc(zval *obj, zval **table, int *n) /* {{{ */
  388. {
  389. zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
  390. *table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL;
  391. *n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0;
  392. return (closure->func.type == ZEND_USER_FUNCTION) ?
  393. closure->func.op_array.static_variables : NULL;
  394. }
  395. /* }}} */
  396. /* {{{ proto Closure::__construct()
  397. Private constructor preventing instantiation */
  398. ZEND_COLD ZEND_METHOD(Closure, __construct)
  399. {
  400. zend_throw_error(NULL, "Instantiation of 'Closure' is not allowed");
  401. }
  402. /* }}} */
  403. ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
  404. ZEND_ARG_INFO(0, newthis)
  405. ZEND_ARG_INFO(0, newscope)
  406. ZEND_END_ARG_INFO()
  407. ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
  408. ZEND_ARG_INFO(0, closure)
  409. ZEND_ARG_INFO(0, newthis)
  410. ZEND_ARG_INFO(0, newscope)
  411. ZEND_END_ARG_INFO()
  412. ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_call, 0, 0, 1)
  413. ZEND_ARG_INFO(0, newthis)
  414. ZEND_ARG_VARIADIC_INFO(0, parameters)
  415. ZEND_END_ARG_INFO()
  416. static const zend_function_entry closure_functions[] = {
  417. ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
  418. ZEND_ME(Closure, bind, arginfo_closure_bind, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
  419. ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
  420. ZEND_ME(Closure, call, arginfo_closure_call, ZEND_ACC_PUBLIC)
  421. ZEND_FE_END
  422. };
  423. void zend_register_closure_ce(void) /* {{{ */
  424. {
  425. zend_class_entry ce;
  426. INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
  427. zend_ce_closure = zend_register_internal_class(&ce);
  428. zend_ce_closure->ce_flags |= ZEND_ACC_FINAL;
  429. zend_ce_closure->create_object = zend_closure_new;
  430. zend_ce_closure->serialize = zend_class_serialize_deny;
  431. zend_ce_closure->unserialize = zend_class_unserialize_deny;
  432. memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
  433. closure_handlers.free_obj = zend_closure_free_storage;
  434. closure_handlers.clone_obj = NULL;
  435. closure_handlers.get_constructor = zend_closure_get_constructor;
  436. closure_handlers.get_method = zend_closure_get_method;
  437. closure_handlers.write_property = zend_closure_write_property;
  438. closure_handlers.read_property = zend_closure_read_property;
  439. closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
  440. closure_handlers.has_property = zend_closure_has_property;
  441. closure_handlers.unset_property = zend_closure_unset_property;
  442. closure_handlers.compare_objects = zend_closure_compare_objects;
  443. closure_handlers.clone_obj = zend_closure_clone;
  444. closure_handlers.get_debug_info = zend_closure_get_debug_info;
  445. closure_handlers.get_closure = zend_closure_get_closure;
  446. closure_handlers.get_gc = zend_closure_get_gc;
  447. }
  448. /* }}} */
  449. static void zend_closure_internal_handler(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
  450. {
  451. zend_closure *closure = (zend_closure*)EX(func)->common.prototype;
  452. closure->orig_internal_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  453. OBJ_RELEASE((zend_object*)closure);
  454. EX(func) = NULL;
  455. }
  456. /* }}} */
  457. ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zend_class_entry *called_scope, zval *this_ptr) /* {{{ */
  458. {
  459. zend_closure *closure;
  460. object_init_ex(res, zend_ce_closure);
  461. closure = (zend_closure *)Z_OBJ_P(res);
  462. if ((scope == NULL) && this_ptr && (Z_TYPE_P(this_ptr) != IS_UNDEF)) {
  463. /* use dummy scope if we're binding an object without specifying a scope */
  464. /* maybe it would be better to create one for this purpose */
  465. scope = zend_ce_closure;
  466. }
  467. if (func->type == ZEND_USER_FUNCTION) {
  468. memcpy(&closure->func, func, sizeof(zend_op_array));
  469. closure->func.common.prototype = (zend_function*)closure;
  470. closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
  471. if (closure->func.op_array.static_variables) {
  472. HashTable *static_variables = closure->func.op_array.static_variables;
  473. ALLOC_HASHTABLE(closure->func.op_array.static_variables);
  474. zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
  475. zend_hash_apply_with_arguments(static_variables, zval_copy_static_var, 1, closure->func.op_array.static_variables);
  476. }
  477. if (UNEXPECTED(!closure->func.op_array.run_time_cache)) {
  478. closure->func.op_array.run_time_cache = func->op_array.run_time_cache = zend_arena_alloc(&CG(arena), func->op_array.cache_size);
  479. memset(func->op_array.run_time_cache, 0, func->op_array.cache_size);
  480. }
  481. if (closure->func.op_array.refcount) {
  482. (*closure->func.op_array.refcount)++;
  483. }
  484. } else {
  485. memcpy(&closure->func, func, sizeof(zend_internal_function));
  486. closure->func.common.prototype = (zend_function*)closure;
  487. closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
  488. /* wrap internal function handler to avoid memory leak */
  489. if (UNEXPECTED(closure->func.internal_function.handler == zend_closure_internal_handler)) {
  490. /* avoid infinity recursion, by taking handler from nested closure */
  491. zend_closure *nested = (zend_closure*)((char*)func - XtOffsetOf(zend_closure, func));
  492. ZEND_ASSERT(nested->std.ce == zend_ce_closure);
  493. closure->orig_internal_handler = nested->orig_internal_handler;
  494. } else {
  495. closure->orig_internal_handler = closure->func.internal_function.handler;
  496. }
  497. closure->func.internal_function.handler = zend_closure_internal_handler;
  498. /* verify that we aren't binding internal function to a wrong scope */
  499. if(func->common.scope != NULL) {
  500. if(scope && !instanceof_function(scope, func->common.scope)) {
  501. zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s", ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name), ZSTR_VAL(scope->name));
  502. scope = NULL;
  503. }
  504. if(scope && this_ptr && (func->common.fn_flags & ZEND_ACC_STATIC) == 0 &&
  505. !instanceof_function(Z_OBJCE_P(this_ptr), closure->func.common.scope)) {
  506. zend_error(E_WARNING, "Cannot bind function %s::%s to object of class %s", ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name), ZSTR_VAL(Z_OBJCE_P(this_ptr)->name));
  507. scope = NULL;
  508. this_ptr = NULL;
  509. }
  510. } else {
  511. /* if it's a free function, we won't set scope & this since they're meaningless */
  512. this_ptr = NULL;
  513. scope = NULL;
  514. }
  515. }
  516. ZVAL_UNDEF(&closure->this_ptr);
  517. /* Invariant:
  518. * If the closure is unscoped or static, it has no bound object. */
  519. closure->func.common.scope = scope;
  520. closure->called_scope = called_scope;
  521. if (scope) {
  522. closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
  523. if (this_ptr && Z_TYPE_P(this_ptr) == IS_OBJECT && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
  524. ZVAL_COPY(&closure->this_ptr, this_ptr);
  525. }
  526. }
  527. }
  528. /* }}} */
  529. /*
  530. * Local variables:
  531. * tab-width: 4
  532. * c-basic-offset: 4
  533. * indent-tabs-mode: t
  534. * End:
  535. */