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

Generated by: LCOV version 1.10

Generated at Tue, 14 Apr 2015 11:48:39 +0000 (12 days ago)

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