root/Zend/zend_closures.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_METHOD
  2. ZEND_METHOD
  3. zend_closure_get_constructor
  4. zend_closure_compare_objects
  5. zend_get_closure_invoke_method
  6. zend_get_closure_method_def
  7. zend_get_closure_this_ptr
  8. zend_closure_get_method
  9. zend_closure_read_property
  10. zend_closure_write_property
  11. zend_closure_get_property_ptr_ptr
  12. zend_closure_has_property
  13. zend_closure_unset_property
  14. zend_closure_free_storage
  15. zend_closure_new
  16. zend_closure_clone
  17. zend_closure_get_closure
  18. zend_closure_get_debug_info
  19. zend_closure_get_gc
  20. ZEND_METHOD
  21. zend_register_closure_ce
  22. zend_create_closure

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend Engine                                                          |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 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 
  21 /* $Id$ */
  22 
  23 #include "zend.h"
  24 #include "zend_API.h"
  25 #include "zend_closures.h"
  26 #include "zend_exceptions.h"
  27 #include "zend_interfaces.h"
  28 #include "zend_objects.h"
  29 #include "zend_objects_API.h"
  30 #include "zend_globals.h"
  31 
  32 #define ZEND_CLOSURE_PRINT_NAME "Closure object"
  33 
  34 #define ZEND_CLOSURE_PROPERTY_ERROR() \
  35         zend_error(E_RECOVERABLE_ERROR, "Closure object cannot have properties")
  36 
  37 typedef struct _zend_closure {
  38         zend_object    std;
  39         zend_function  func;
  40         zval          *this_ptr;
  41         HashTable     *debug_info;
  42 } zend_closure;
  43 
  44 /* non-static since it needs to be referenced */
  45 ZEND_API zend_class_entry *zend_ce_closure;
  46 static zend_object_handlers closure_handlers;
  47 
  48 ZEND_METHOD(Closure, __invoke) /* {{{ */
  49 {
  50         zend_function *func = EG(current_execute_data)->function_state.function;
  51         zval ***arguments;
  52         zval *closure_result_ptr = NULL;
  53 
  54         arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS());
  55         if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
  56                 efree(arguments);
  57                 zend_error(E_RECOVERABLE_ERROR, "Cannot get arguments for calling closure");
  58                 RETVAL_FALSE;
  59         } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
  60                 RETVAL_FALSE;
  61         } else if (closure_result_ptr) {
  62                 zval_ptr_dtor(&return_value);
  63                 *return_value_ptr = closure_result_ptr;
  64         }
  65         efree(arguments);
  66 
  67         /* destruct the function also, then - we have allocated it in get_method */
  68         efree((char*)func->internal_function.function_name);
  69         efree(func);
  70 }
  71 /* }}} */
  72 
  73 /* {{{ proto Closure Closure::bind(Closure $old, object $to [, mixed $scope = "static" ] )
  74    Create a closure from another one and bind to another object and scope */
  75 ZEND_METHOD(Closure, bind)
  76 {
  77         zval *newthis, *zclosure, *scope_arg = NULL;
  78         zend_closure *closure;
  79         zend_class_entry *ce, **ce_p;
  80 
  81         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
  82                 RETURN_NULL();
  83         }
  84 
  85         closure = (zend_closure *)zend_object_store_get_object(zclosure TSRMLS_CC);
  86 
  87         if ((newthis != NULL) && (closure->func.common.fn_flags & ZEND_ACC_STATIC)) {
  88                 zend_error(E_WARNING, "Cannot bind an instance to a static closure");
  89         }
  90 
  91         if (newthis == NULL && !(closure->func.common.fn_flags & ZEND_ACC_STATIC)
  92                         && closure->func.common.scope && closure->func.type == ZEND_INTERNAL_FUNCTION) {
  93                 zend_error(E_WARNING, "Cannot unbind $this of internal method");
  94                 return;
  95         }
  96 
  97         if (scope_arg != NULL) { /* scope argument was given */
  98                 if (IS_ZEND_STD_OBJECT(*scope_arg)) {
  99                         ce = Z_OBJCE_P(scope_arg);
 100                 } else if (Z_TYPE_P(scope_arg) == IS_NULL) {
 101                         ce = NULL;
 102                 } else {
 103                         char *class_name;
 104                         int class_name_len;
 105                         zval tmp_zval;
 106                         INIT_ZVAL(tmp_zval);
 107 
 108                         if (Z_TYPE_P(scope_arg) == IS_STRING) {
 109                                 class_name = Z_STRVAL_P(scope_arg);
 110                                 class_name_len = Z_STRLEN_P(scope_arg);
 111                         } else {
 112                                 tmp_zval = *scope_arg;
 113                                 zval_copy_ctor(&tmp_zval);
 114                                 convert_to_string(&tmp_zval);
 115                                 class_name = Z_STRVAL(tmp_zval);
 116                                 class_name_len = Z_STRLEN(tmp_zval);
 117                         }
 118 
 119                         if ((class_name_len == sizeof("static") - 1) &&
 120                                 (memcmp("static", class_name, sizeof("static") - 1) == 0)) {
 121                                 ce = closure->func.common.scope;
 122                         }
 123                         else if (zend_lookup_class_ex(class_name, class_name_len, NULL, 1, &ce_p TSRMLS_CC) == FAILURE) {
 124                                 zend_error(E_WARNING, "Class '%s' not found", class_name);
 125                                 zval_dtor(&tmp_zval);
 126                                 RETURN_NULL();
 127                         } else {
 128                                 ce = *ce_p;
 129                         }
 130                         zval_dtor(&tmp_zval);
 131                 }
 132         } else { /* scope argument not given; do not change the scope by default */
 133                 ce = closure->func.common.scope;
 134         }
 135 
 136         /* verify that we aren't binding internal function to a wrong scope */
 137         if (closure->func.type == ZEND_INTERNAL_FUNCTION && closure->func.common.scope != NULL) {
 138                 if (ce && !instanceof_function(ce, closure->func.common.scope TSRMLS_CC)) {
 139                         zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s", closure->func.common.scope->name, closure->func.common.function_name, ce->name);
 140                         return;
 141                 }
 142                 if (ce && newthis && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0 &&
 143                                 !instanceof_function(Z_OBJCE_P(newthis), closure->func.common.scope TSRMLS_CC)) {
 144                         zend_error(E_WARNING, "Cannot bind internal method %s::%s() to object of class %s", closure->func.common.scope->name, closure->func.common.function_name, Z_OBJCE_P(newthis)->name);
 145                         return;
 146                 }
 147         }
 148 
 149         zend_create_closure(return_value, &closure->func, ce, newthis TSRMLS_CC);
 150 }
 151 /* }}} */
 152 
 153 static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
 154 {
 155         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
 156         return NULL;
 157 }
 158 /* }}} */
 159 
 160 static int zend_closure_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
 161 {
 162         return (Z_OBJ_HANDLE_P(o1) != Z_OBJ_HANDLE_P(o2));
 163 }
 164 /* }}} */
 165 
 166 ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {{{ */
 167 {
 168         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
 169         zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
 170         const zend_uint keep_flags = ZEND_ACC_RETURN_REFERENCE | ZEND_ACC_VARIADIC;
 171 
 172         invoke->common = closure->func.common;
 173         invoke->type = ZEND_INTERNAL_FUNCTION;
 174         invoke->internal_function.fn_flags =
 175                 ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & keep_flags);
 176         invoke->internal_function.handler = ZEND_MN(Closure___invoke);
 177         invoke->internal_function.module = 0;
 178         invoke->internal_function.scope = zend_ce_closure;
 179         invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
 180         return invoke;
 181 }
 182 /* }}} */
 183 
 184 ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC) /* {{{ */
 185 {
 186         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
 187         return &closure->func;
 188 }
 189 /* }}} */
 190 
 191 ZEND_API zval* zend_get_closure_this_ptr(zval *obj TSRMLS_DC) /* {{{ */
 192 {
 193         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
 194         return closure->this_ptr;
 195 }
 196 /* }}} */
 197 
 198 static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */
 199 {
 200         char *lc_name;
 201         ALLOCA_FLAG(use_heap)
 202 
 203         lc_name = do_alloca(method_len + 1, use_heap);
 204         zend_str_tolower_copy(lc_name, method_name, method_len);
 205         if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
 206                 memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
 207         ) {
 208                 free_alloca(lc_name, use_heap);
 209                 return zend_get_closure_invoke_method(*object_ptr TSRMLS_CC);
 210         }
 211         free_alloca(lc_name, use_heap);
 212         return std_object_handlers.get_method(object_ptr, method_name, method_len, key TSRMLS_CC);
 213 }
 214 /* }}} */
 215 
 216 static zval *zend_closure_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
 217 {
 218         ZEND_CLOSURE_PROPERTY_ERROR();
 219         Z_ADDREF(EG(uninitialized_zval));
 220         return &EG(uninitialized_zval);
 221 }
 222 /* }}} */
 223 
 224 static void zend_closure_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
 225 {
 226         ZEND_CLOSURE_PROPERTY_ERROR();
 227 }
 228 /* }}} */
 229 
 230 static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
 231 {
 232         ZEND_CLOSURE_PROPERTY_ERROR();
 233         return NULL;
 234 }
 235 /* }}} */
 236 
 237 static int zend_closure_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
 238 {
 239         if (has_set_exists != 2) {
 240                 ZEND_CLOSURE_PROPERTY_ERROR();
 241         }
 242         return 0;
 243 }
 244 /* }}} */
 245 
 246 static void zend_closure_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
 247 {
 248         ZEND_CLOSURE_PROPERTY_ERROR();
 249 }
 250 /* }}} */
 251 
 252 static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */
 253 {
 254         zend_closure *closure = (zend_closure *)object;
 255 
 256         zend_object_std_dtor(&closure->std TSRMLS_CC);
 257 
 258         if (closure->func.type == ZEND_USER_FUNCTION) {
 259                 zend_execute_data *ex = EG(current_execute_data);
 260                 while (ex) {
 261                         if (ex->op_array == &closure->func.op_array) {
 262                                 zend_error(E_ERROR, "Cannot destroy active lambda function");
 263                         }
 264                         ex = ex->prev_execute_data;
 265                 }
 266                 destroy_op_array(&closure->func.op_array TSRMLS_CC);
 267         }
 268 
 269         if (closure->debug_info != NULL) {
 270                 zend_hash_destroy(closure->debug_info);
 271                 efree(closure->debug_info);
 272         }
 273 
 274         if (closure->this_ptr) {
 275                 zval_ptr_dtor(&closure->this_ptr);
 276         }
 277 
 278         efree(closure);
 279 }
 280 /* }}} */
 281 
 282 static zend_object_value zend_closure_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
 283 {
 284         zend_closure *closure;
 285         zend_object_value object;
 286 
 287         closure = emalloc(sizeof(zend_closure));
 288         memset(closure, 0, sizeof(zend_closure));
 289 
 290         zend_object_std_init(&closure->std, class_type TSRMLS_CC);
 291 
 292         object.handle = zend_objects_store_put(closure, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_closure_free_storage, NULL TSRMLS_CC);
 293         object.handlers = &closure_handlers;
 294 
 295         return object;
 296 }
 297 /* }}} */
 298 
 299 static zend_object_value zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */
 300 {
 301         zend_closure *closure = (zend_closure *)zend_object_store_get_object(zobject TSRMLS_CC);
 302         zval result;
 303 
 304         zend_create_closure(&result, &closure->func, closure->func.common.scope, closure->this_ptr TSRMLS_CC);
 305         return Z_OBJVAL(result);
 306 }
 307 /* }}} */
 308 
 309 int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
 310 {
 311         zend_closure *closure;
 312 
 313         if (Z_TYPE_P(obj) != IS_OBJECT) {
 314                 return FAILURE;
 315         }
 316 
 317         closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
 318         *fptr_ptr = &closure->func;
 319 
 320         if (closure->this_ptr) {
 321                 if (zobj_ptr) {
 322                         *zobj_ptr = closure->this_ptr;
 323                 }
 324                 *ce_ptr = Z_OBJCE_P(closure->this_ptr);
 325         } else {
 326                 if (zobj_ptr) {
 327                         *zobj_ptr = NULL;
 328                 }
 329                 *ce_ptr = closure->func.common.scope;
 330         }
 331         return SUCCESS;
 332 }
 333 /* }}} */
 334 
 335 static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
 336 {
 337         zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
 338         zval *val;
 339         struct _zend_arg_info *arg_info = closure->func.common.arg_info;
 340 
 341         *is_temp = 0;
 342 
 343         if (closure->debug_info == NULL) {
 344                 ALLOC_HASHTABLE(closure->debug_info);
 345                 zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
 346         }
 347         if (closure->debug_info->nApplyCount == 0) {
 348                 if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
 349                         HashTable *static_variables = closure->func.op_array.static_variables;
 350                         MAKE_STD_ZVAL(val);
 351                         array_init(val);
 352                         zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
 353                         zend_hash_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
 354                 }
 355 
 356                 if (closure->this_ptr) {
 357                         Z_ADDREF_P(closure->this_ptr);
 358                         zend_symtable_update(closure->debug_info, "this", sizeof("this"), (void *) &closure->this_ptr, sizeof(zval *), NULL);
 359                 }
 360 
 361                 if (arg_info) {
 362                         zend_uint i, required = closure->func.common.required_num_args;
 363 
 364                         MAKE_STD_ZVAL(val);
 365                         array_init(val);
 366 
 367                         for (i = 0; i < closure->func.common.num_args; i++) {
 368                                 char *name, *info;
 369                                 int name_len, info_len;
 370                                 if (arg_info->name) {
 371                                         name_len = zend_spprintf(&name, 0, "%s$%s",
 372                                                                         arg_info->pass_by_reference ? "&" : "",
 373                                                                         arg_info->name);
 374                                 } else {
 375                                         name_len = zend_spprintf(&name, 0, "%s$param%d",
 376                                                                         arg_info->pass_by_reference ? "&" : "",
 377                                                                         i + 1);
 378                                 }
 379                                 info_len = zend_spprintf(&info, 0, "%s",
 380                                                                 i >= required ? "<optional>" : "<required>");
 381                                 add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
 382                                 efree(name);
 383                                 arg_info++;
 384                         }
 385                         zend_hash_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
 386                 }
 387         }
 388 
 389         return closure->debug_info;
 390 }
 391 /* }}} */
 392 
 393 static HashTable *zend_closure_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{ */
 394 {
 395         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
 396 
 397         *table = closure->this_ptr ? &closure->this_ptr : NULL;
 398         *n = closure->this_ptr ? 1 : 0;
 399         return (closure->func.type == ZEND_USER_FUNCTION) ?
 400                 closure->func.op_array.static_variables : NULL;
 401 }
 402 /* }}} */
 403 
 404 /* {{{ proto Closure::__construct()
 405    Private constructor preventing instantiation */
 406 ZEND_METHOD(Closure, __construct)
 407 {
 408         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
 409 }
 410 /* }}} */
 411 
 412 ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
 413         ZEND_ARG_INFO(0, newthis)
 414         ZEND_ARG_INFO(0, newscope)
 415 ZEND_END_ARG_INFO()
 416 
 417 ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
 418         ZEND_ARG_INFO(0, closure)
 419         ZEND_ARG_INFO(0, newthis)
 420         ZEND_ARG_INFO(0, newscope)
 421 ZEND_END_ARG_INFO()
 422 
 423 static const zend_function_entry closure_functions[] = {
 424         ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
 425         ZEND_ME(Closure, bind, arginfo_closure_bind, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
 426         ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
 427         {NULL, NULL, NULL}
 428 };
 429 
 430 void zend_register_closure_ce(TSRMLS_D) /* {{{ */
 431 {
 432         zend_class_entry ce;
 433 
 434         INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
 435         zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
 436         zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
 437         zend_ce_closure->create_object = zend_closure_new;
 438         zend_ce_closure->serialize = zend_class_serialize_deny;
 439         zend_ce_closure->unserialize = zend_class_unserialize_deny;
 440 
 441         memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
 442         closure_handlers.get_constructor = zend_closure_get_constructor;
 443         closure_handlers.get_method = zend_closure_get_method;
 444         closure_handlers.write_property = zend_closure_write_property;
 445         closure_handlers.read_property = zend_closure_read_property;
 446         closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
 447         closure_handlers.has_property = zend_closure_has_property;
 448         closure_handlers.unset_property = zend_closure_unset_property;
 449         closure_handlers.compare_objects = zend_closure_compare_objects;
 450         closure_handlers.clone_obj = zend_closure_clone;
 451         closure_handlers.get_debug_info = zend_closure_get_debug_info;
 452         closure_handlers.get_closure = zend_closure_get_closure;
 453         closure_handlers.get_gc = zend_closure_get_gc;
 454 }
 455 /* }}} */
 456 
 457 ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zval *this_ptr TSRMLS_DC) /* {{{ */
 458 {
 459         zend_closure *closure;
 460 
 461         object_init_ex(res, zend_ce_closure);
 462 
 463         closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);
 464 
 465         closure->func = *func;
 466         closure->func.common.prototype = NULL;
 467         closure->func.common.fn_flags |= ZEND_ACC_CLOSURE;
 468 
 469         if ((scope == NULL) && (this_ptr != NULL)) {
 470                 /* use dummy scope if we're binding an object without specifying a scope */
 471                 /* maybe it would be better to create one for this purpose */
 472                 scope = zend_ce_closure;
 473         }
 474 
 475         if (closure->func.type == ZEND_USER_FUNCTION) {
 476                 if (closure->func.op_array.static_variables) {
 477                         HashTable *static_variables = closure->func.op_array.static_variables;
 478 
 479                         ALLOC_HASHTABLE(closure->func.op_array.static_variables);
 480                         zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
 481                         zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, closure->func.op_array.static_variables);
 482                 }
 483                 closure->func.op_array.run_time_cache = NULL;
 484                 (*closure->func.op_array.refcount)++;
 485         } else {
 486                 if (!func->common.scope) {
 487                         /* if it's a free function, we won't set scope & this since they're meaningless */
 488                         this_ptr = NULL;
 489                         scope = NULL;
 490                 }
 491         }
 492 
 493         closure->this_ptr = NULL;
 494         /* Invariants:
 495          * If the closure is unscoped, it has no bound object.
 496          * The the closure is scoped, it's either static or it's bound */
 497         closure->func.common.scope = scope;
 498         if (scope) {
 499                 closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
 500                 if (this_ptr && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
 501                         closure->this_ptr = this_ptr;
 502                         Z_ADDREF_P(this_ptr);
 503                 } else {
 504                         closure->func.common.fn_flags |= ZEND_ACC_STATIC;
 505                 }
 506         }
 507 }
 508 /* }}} */
 509 
 510 /*
 511  * Local variables:
 512  * tab-width: 4
 513  * c-basic-offset: 4
 514  * indent-tabs-mode: t
 515  * End:
 516  */

/* [<][>][^][v][top][bottom][index][help] */