PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_closures.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 220 259 84.9 %
Date: 2015-09-02 Functions: 18 23 78.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Wed, 02 Sep 2015 17:19:07 +0000 (17 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.