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: 199 243 81.9 %
Date: 2015-01-18 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          23 : ZEND_API const zend_function *zend_get_closure_method_def(zval *obj) /* {{{ */
     197             : {
     198          23 :         zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
     199          23 :         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         404 : static void zend_closure_free_storage(zend_object *object) /* {{{ */
     260             : {
     261         404 :         zend_closure *closure = (zend_closure *)object;
     262             : 
     263         404 :         zend_object_std_dtor(&closure->std);
     264             : 
     265         404 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     266         400 :                 zend_execute_data *ex = EG(current_execute_data);
     267        1011 :                 while (ex) {
     268         212 :                         if (ex->func == &closure->func) {
     269           1 :                                 zend_error(E_ERROR, "Cannot destroy active lambda function");
     270             :                         }
     271         211 :                         ex = ex->prev_execute_data;
     272             :                 }
     273         399 :                 destroy_op_array(&closure->func.op_array);
     274             :         }
     275             : 
     276         403 :         if (closure->debug_info != NULL) {
     277          18 :                 zend_hash_destroy(closure->debug_info);
     278          18 :                 efree(closure->debug_info);
     279             :         }
     280             : 
     281         806 :         if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
     282          55 :                 zval_ptr_dtor(&closure->this_ptr);
     283             :         }
     284         403 : }
     285             : /* }}} */
     286             : 
     287         404 : static zend_object *zend_closure_new(zend_class_entry *class_type) /* {{{ */
     288             : {
     289             :         zend_closure *closure;
     290             : 
     291         404 :         closure = emalloc(sizeof(zend_closure));
     292         404 :         memset(closure, 0, sizeof(zend_closure));
     293             : 
     294         404 :         zend_object_std_init(&closure->std, class_type);
     295         404 :         closure->std.handlers = &closure_handlers;
     296             : 
     297         404 :         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         741 : 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         741 :         if (Z_TYPE_P(obj) != IS_OBJECT) {
     316           0 :                 return FAILURE;
     317             :         }
     318             : 
     319         741 :         closure = (zend_closure *)Z_OBJ_P(obj);
     320         741 :         *fptr_ptr = &closure->func;
     321             : 
     322        1482 :         if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
     323          62 :                 if (obj_ptr) {
     324          62 :                         *obj_ptr = Z_OBJ(closure->this_ptr);
     325             :                 }
     326          62 :                 *ce_ptr = Z_OBJCE(closure->this_ptr);
     327             :         } else {
     328         679 :                 if (obj_ptr) {
     329         679 :                         *obj_ptr = NULL;
     330             :                 }
     331         679 :                 *ce_ptr = closure->func.common.scope;
     332             :         }
     333         741 :         return SUCCESS;
     334             : }
     335             : /* }}} */
     336             : 
     337          26 : static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp) /* {{{ */
     338             : {
     339          26 :         zend_closure *closure = (zend_closure *)Z_OBJ_P(object);
     340             :         zval val;
     341          26 :         struct _zend_arg_info *arg_info = closure->func.common.arg_info;
     342             : 
     343          26 :         *is_temp = 0;
     344             : 
     345          26 :         if (closure->debug_info == NULL) {
     346          18 :                 ALLOC_HASHTABLE(closure->debug_info);
     347          18 :                 zend_hash_init(closure->debug_info, 8, NULL, ZVAL_PTR_DTOR, 0);
     348             :         }
     349          26 :         if (closure->debug_info->u.v.nApplyCount == 0) {
     350          23 :                 if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
     351           6 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     352           6 :                         ZVAL_NEW_ARR(&val);
     353           6 :                         zend_array_dup(Z_ARRVAL(val), static_variables);
     354           6 :                         zend_hash_str_update(closure->debug_info, "static", sizeof("static")-1, &val);
     355             :                 }
     356             : 
     357          46 :                 if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
     358           3 :                         Z_ADDREF(closure->this_ptr);
     359           3 :                         zend_hash_str_update(closure->debug_info, "this", sizeof("this")-1, &closure->this_ptr);
     360             :                 }
     361             : 
     362          23 :                 if (arg_info) {
     363           4 :                         uint32_t i, num_args, required = closure->func.common.required_num_args;
     364             : 
     365           4 :                         array_init(&val);
     366             : 
     367           4 :                         num_args = closure->func.common.num_args;
     368           4 :                         if (closure->func.common.fn_flags & ZEND_ACC_VARIADIC) {
     369           0 :                                 num_args++;
     370             :                         }
     371          10 :                         for (i = 0; i < num_args; i++) {
     372             :                                 zend_string *name;
     373             :                                 zval info;
     374           6 :                                 if (arg_info->name) {
     375          12 :                                         name = zend_strpprintf(0, "%s$%s",
     376           6 :                                                         arg_info->pass_by_reference ? "&" : "",
     377           6 :                                                         arg_info->name->val);
     378             :                                 } else {
     379           0 :                                         name = zend_strpprintf(0, "%s$param%d",
     380           0 :                                                         arg_info->pass_by_reference ? "&" : "",
     381             :                                                         i + 1);
     382             :                                 }
     383           6 :                                 ZVAL_NEW_STR(&info, zend_strpprintf(0, "%s", i >= required ? "<optional>" : "<required>"));
     384           6 :                                 zend_hash_update(Z_ARRVAL(val), name, &info);
     385             :                                 zend_string_release(name);
     386           6 :                                 arg_info++;
     387             :                         }
     388           4 :                         zend_hash_str_update(closure->debug_info, "parameter", sizeof("parameter")-1, &val);
     389             :                 }
     390             :         }
     391             : 
     392          26 :         return closure->debug_info;
     393             : }
     394             : /* }}} */
     395             : 
     396           6 : static HashTable *zend_closure_get_gc(zval *obj, zval **table, int *n) /* {{{ */
     397             : {
     398           6 :         zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
     399             : 
     400           6 :         if (closure->debug_info != NULL) {
     401           0 :                 zend_hash_destroy(closure->debug_info);
     402           0 :                 efree(closure->debug_info);
     403           0 :                 closure->debug_info = NULL;
     404             :         }
     405             : 
     406          12 :         *table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL;
     407          12 :         *n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0;
     408           6 :         return (closure->func.type == ZEND_USER_FUNCTION) ?
     409             :                 closure->func.op_array.static_variables : NULL;
     410             : }
     411             : /* }}} */
     412             : 
     413             : /* {{{ proto Closure::__construct()
     414             :    Private constructor preventing instantiation */
     415           0 : ZEND_METHOD(Closure, __construct)
     416             : {
     417           0 :         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
     418           0 : }
     419             : /* }}} */
     420             : 
     421             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
     422             :         ZEND_ARG_INFO(0, newthis)
     423             :         ZEND_ARG_INFO(0, newscope)
     424             : ZEND_END_ARG_INFO()
     425             : 
     426             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
     427             :         ZEND_ARG_INFO(0, closure)
     428             :         ZEND_ARG_INFO(0, newthis)
     429             :         ZEND_ARG_INFO(0, newscope)
     430             : ZEND_END_ARG_INFO()
     431             : 
     432             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_call, 0, 0, 1)
     433             :         ZEND_ARG_INFO(0, newthis)
     434             :         ZEND_ARG_VARIADIC_INFO(0, parameters)
     435             : ZEND_END_ARG_INFO()
     436             : 
     437             : static const zend_function_entry closure_functions[] = {
     438             :         ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
     439             :         ZEND_ME(Closure, bind, arginfo_closure_bind, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     440             :         ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
     441             :         ZEND_ME(Closure, call, arginfo_closure_call, ZEND_ACC_PUBLIC)
     442             :         ZEND_FE_END
     443             : };
     444             : 
     445       20688 : void zend_register_closure_ce(void) /* {{{ */
     446             : {
     447             :         zend_class_entry ce;
     448             : 
     449       20688 :         INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
     450       20688 :         zend_ce_closure = zend_register_internal_class(&ce);
     451       20688 :         zend_ce_closure->ce_flags |= ZEND_ACC_FINAL;
     452       20688 :         zend_ce_closure->create_object = zend_closure_new;
     453       20688 :         zend_ce_closure->serialize = zend_class_serialize_deny;
     454       20688 :         zend_ce_closure->unserialize = zend_class_unserialize_deny;
     455             : 
     456       20688 :         memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
     457       20688 :         closure_handlers.free_obj = zend_closure_free_storage;
     458       20688 :         closure_handlers.clone_obj = NULL;
     459       20688 :         closure_handlers.get_constructor = zend_closure_get_constructor;
     460       20688 :         closure_handlers.get_method = zend_closure_get_method;
     461       20688 :         closure_handlers.write_property = zend_closure_write_property;
     462       20688 :         closure_handlers.read_property = zend_closure_read_property;
     463       20688 :         closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
     464       20688 :         closure_handlers.has_property = zend_closure_has_property;
     465       20688 :         closure_handlers.unset_property = zend_closure_unset_property;
     466       20688 :         closure_handlers.compare_objects = zend_closure_compare_objects;
     467       20688 :         closure_handlers.clone_obj = zend_closure_clone;
     468       20688 :         closure_handlers.get_debug_info = zend_closure_get_debug_info;
     469       20688 :         closure_handlers.get_closure = zend_closure_get_closure;
     470       20688 :         closure_handlers.get_gc = zend_closure_get_gc;
     471       20688 : }
     472             : /* }}} */
     473             : 
     474         400 : ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zval *this_ptr) /* {{{ */
     475             : {
     476             :         zend_closure *closure;
     477             : 
     478         400 :         object_init_ex(res, zend_ce_closure);
     479             : 
     480         400 :         closure = (zend_closure *)Z_OBJ_P(res);
     481             : 
     482         400 :         closure->func = *func;
     483         400 :         closure->func.common.prototype = NULL;
     484             : 
     485         414 :         if ((scope == NULL) && this_ptr && (Z_TYPE_P(this_ptr) != IS_UNDEF)) {
     486             :                 /* use dummy scope if we're binding an object without specifying a scope */
     487             :                 /* maybe it would be better to create one for this purpose */
     488          12 :                 scope = zend_ce_closure;
     489             :         }
     490             : 
     491         400 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     492         400 :                 if (closure->func.op_array.static_variables) {
     493         116 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     494             : 
     495         116 :                         ALLOC_HASHTABLE(closure->func.op_array.static_variables);
     496         116 :                         zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
     497         116 :                         zend_hash_apply_with_arguments(static_variables, zval_copy_static_var, 1, closure->func.op_array.static_variables);
     498             :                 }
     499         400 :                 closure->func.op_array.run_time_cache = NULL;
     500         400 :                 (*closure->func.op_array.refcount)++;
     501             :         } else {
     502             :                 /* verify that we aren't binding internal function to a wrong scope */
     503           0 :                 if(func->common.scope != NULL) {
     504           0 :                         if(scope && !instanceof_function(scope, func->common.scope)) {
     505           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);
     506           0 :                                 scope = NULL;
     507             :                         }
     508           0 :                         if(scope && this_ptr && (func->common.fn_flags & ZEND_ACC_STATIC) == 0 &&
     509           0 :                                         !instanceof_function(Z_OBJCE_P(this_ptr), closure->func.common.scope)) {
     510           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);
     511           0 :                                 scope = NULL;
     512           0 :                                 this_ptr = NULL;
     513             :                         }
     514             :                 } else {
     515             :                         /* if it's a free function, we won't set scope & this since they're meaningless */
     516           0 :                         this_ptr = NULL;
     517           0 :                         scope = NULL;
     518             :                 }
     519             :         }
     520             : 
     521         400 :         ZVAL_UNDEF(&closure->this_ptr);
     522             :         /* Invariants:
     523             :          * If the closure is unscoped, it has no bound object.
     524             :          * The the closure is scoped, it's either static or it's bound */
     525         400 :         closure->func.common.scope = scope;
     526         400 :         if (scope) {
     527          93 :                 closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
     528         213 :                 if (this_ptr && Z_TYPE_P(this_ptr) == IS_OBJECT && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
     529          55 :                         ZVAL_COPY(&closure->this_ptr, this_ptr);
     530             :                 } else {
     531          38 :                         closure->func.common.fn_flags |= ZEND_ACC_STATIC;
     532             :                 }
     533             :         }
     534         400 : }
     535             : /* }}} */
     536             : 
     537             : /*
     538             :  * Local variables:
     539             :  * tab-width: 4
     540             :  * c-basic-offset: 4
     541             :  * indent-tabs-mode: t
     542             :  * End:
     543             :  */

Generated by: LCOV version 1.10

Generated at Sun, 18 Jan 2015 09:00:36 +0000 (8 days ago)

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