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: 197 240 82.1 %
Date: 2014-10-30 Functions: 18 23 78.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2014 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 TSRMLS_CC) == 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() TSRMLS_CC, "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 TSRMLS_CC)) {
      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 TSRMLS_CC) != 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 TSRMLS_CC) == 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() TSRMLS_CC, 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 TSRMLS_CC)) == 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 TSRMLS_CC);
     163             : }
     164             : /* }}} */
     165             : 
     166           0 : static zend_function *zend_closure_get_constructor(zend_object *object TSRMLS_DC) /* {{{ */
     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 TSRMLS_DC) /* {{{ */
     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 TSRMLS_DC) /* {{{ */
     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          34 :         invoke->type = ZEND_INTERNAL_FUNCTION;
     186          34 :         invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & ZEND_ACC_RETURN_REFERENCE);
     187          34 :         invoke->internal_function.handler = ZEND_MN(Closure___invoke);
     188          34 :         invoke->internal_function.module = 0;
     189          34 :         invoke->internal_function.scope = zend_ce_closure;
     190          34 :         invoke->internal_function.function_name = zend_string_init(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1, 0);
     191          34 :         return invoke;
     192             : }
     193             : /* }}} */
     194             : 
     195          23 : ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC) /* {{{ */
     196             : {
     197          23 :         zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
     198          23 :         return &closure->func;
     199             : }
     200             : /* }}} */
     201             : 
     202           3 : ZEND_API zval* zend_get_closure_this_ptr(zval *obj TSRMLS_DC) /* {{{ */
     203             : {
     204           3 :         zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
     205           3 :         return &closure->this_ptr;
     206             : }
     207             : /* }}} */
     208             : 
     209          72 : static zend_function *zend_closure_get_method(zend_object **object, zend_string *method, const zval *key TSRMLS_DC) /* {{{ */
     210             : {
     211             :         zend_string *lc_name;
     212             : 
     213         144 :         lc_name = zend_string_alloc(method->len, 0);
     214          72 :         zend_str_tolower_copy(lc_name->val, method->val, method->len);
     215          72 :         if (zend_string_equals_literal(method, ZEND_INVOKE_FUNC_NAME)) {
     216             :                 zend_string_free(lc_name);
     217          19 :                 return zend_get_closure_invoke_method(*object TSRMLS_CC);
     218             :         }
     219             :         zend_string_free(lc_name);
     220          53 :         return std_object_handlers.get_method(object, method, key TSRMLS_CC);
     221             : }
     222             : /* }}} */
     223             : 
     224           1 : static zval *zend_closure_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv TSRMLS_DC) /* {{{ */
     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 TSRMLS_DC) /* {{{ */
     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 TSRMLS_DC) /* {{{ */
     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 TSRMLS_DC) /* {{{ */
     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 TSRMLS_DC) /* {{{ */
     254             : {
     255           0 :         ZEND_CLOSURE_PROPERTY_ERROR();
     256           0 : }
     257             : /* }}} */
     258             : 
     259         402 : static void zend_closure_free_storage(zend_object *object TSRMLS_DC) /* {{{ */
     260             : {
     261         402 :         zend_closure *closure = (zend_closure *)object;
     262             : 
     263         402 :         zend_object_std_dtor(&closure->std TSRMLS_CC);
     264             : 
     265         402 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     266         398 :                 zend_execute_data *ex = EG(current_execute_data);
     267        1008 :                 while (ex) {
     268         213 :                         if (ex->func == &closure->func) {
     269           1 :                                 zend_error(E_ERROR, "Cannot destroy active lambda function");
     270             :                         }
     271         212 :                         ex = ex->prev_execute_data;
     272             :                 }
     273         397 :                 destroy_op_array(&closure->func.op_array TSRMLS_CC);
     274             :         }
     275             : 
     276         401 :         if (closure->debug_info != NULL) {
     277          18 :                 zend_hash_destroy(closure->debug_info);
     278          18 :                 efree(closure->debug_info);
     279             :         }
     280             : 
     281         802 :         if (Z_TYPE(closure->this_ptr) != IS_UNDEF) {
     282          55 :                 zval_ptr_dtor(&closure->this_ptr);
     283             :         }
     284         401 : }
     285             : /* }}} */
     286             : 
     287         402 : static zend_object *zend_closure_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
     288             : {
     289             :         zend_closure *closure;
     290             : 
     291         402 :         closure = emalloc(sizeof(zend_closure));
     292         402 :         memset(closure, 0, sizeof(zend_closure));
     293             : 
     294         402 :         zend_object_std_init(&closure->std, class_type TSRMLS_CC);
     295         402 :         closure->std.handlers = &closure_handlers;
     296             : 
     297         402 :         return (zend_object*)closure;
     298             : }
     299             : /* }}} */
     300             : 
     301           2 : static zend_object *zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */
     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 TSRMLS_CC);
     307           2 :         return Z_OBJ(result);
     308             : }
     309             : /* }}} */
     310             : 
     311         742 : int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr TSRMLS_DC) /* {{{ */
     312             : {
     313             :         zend_closure *closure;
     314             : 
     315         742 :         if (Z_TYPE_P(obj) != IS_OBJECT) {
     316           0 :                 return FAILURE;
     317             :         }
     318             : 
     319         742 :         closure = (zend_closure *)Z_OBJ_P(obj);
     320         742 :         *fptr_ptr = &closure->func;
     321             : 
     322        1484 :         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         680 :                 if (obj_ptr) {
     329         680 :                         *obj_ptr = NULL;
     330             :                 }
     331         680 :                 *ce_ptr = closure->func.common.scope;
     332             :         }
     333         742 :         return SUCCESS;
     334             : }
     335             : /* }}} */
     336             : 
     337          26 : static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
     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, required = closure->func.common.required_num_args;
     364             : 
     365           4 :                         array_init(&val);
     366             : 
     367          10 :                         for (i = 0; i < closure->func.common.num_args; i++) {
     368             :                                 zend_string *name;
     369             :                                 zval info;
     370           6 :                                 if (arg_info->name) {
     371          12 :                                         name = zend_strpprintf(0, "%s$%s",
     372           6 :                                                         arg_info->pass_by_reference ? "&" : "",
     373             :                                                         arg_info->name);
     374             :                                 } else {
     375           0 :                                         name = zend_strpprintf(0, "%s$param%d",
     376           0 :                                                         arg_info->pass_by_reference ? "&" : "",
     377             :                                                         i + 1);
     378             :                                 }
     379           6 :                                 ZVAL_NEW_STR(&info, zend_strpprintf(0, "%s", i >= required ? "<optional>" : "<required>"));
     380           6 :                                 zend_hash_update(Z_ARRVAL(val), name, &info);
     381             :                                 zend_string_release(name);
     382           6 :                                 arg_info++;
     383             :                         }
     384           4 :                         zend_hash_str_update(closure->debug_info, "parameter", sizeof("parameter")-1, &val);
     385             :                 }
     386             :         }
     387             : 
     388          26 :         return closure->debug_info;
     389             : }
     390             : /* }}} */
     391             : 
     392           6 : static HashTable *zend_closure_get_gc(zval *obj, zval **table, int *n TSRMLS_DC) /* {{{ */
     393             : {
     394           6 :         zend_closure *closure = (zend_closure *)Z_OBJ_P(obj);
     395             : 
     396           6 :         if (closure->debug_info != NULL) {
     397           0 :                 zend_hash_destroy(closure->debug_info);
     398           0 :                 efree(closure->debug_info);
     399           0 :                 closure->debug_info = NULL;
     400             :         }
     401             : 
     402          12 :         *table = Z_TYPE(closure->this_ptr) != IS_NULL ? &closure->this_ptr : NULL;
     403          12 :         *n = Z_TYPE(closure->this_ptr) != IS_NULL ? 1 : 0;
     404           6 :         return (closure->func.type == ZEND_USER_FUNCTION) ?
     405             :                 closure->func.op_array.static_variables : NULL;
     406             : }
     407             : /* }}} */
     408             : 
     409             : /* {{{ proto Closure::__construct()
     410             :    Private constructor preventing instantiation */
     411           0 : ZEND_METHOD(Closure, __construct)
     412             : {
     413           0 :         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
     414           0 : }
     415             : /* }}} */
     416             : 
     417             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
     418             :         ZEND_ARG_INFO(0, newthis)
     419             :         ZEND_ARG_INFO(0, newscope)
     420             : ZEND_END_ARG_INFO()
     421             : 
     422             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
     423             :         ZEND_ARG_INFO(0, closure)
     424             :         ZEND_ARG_INFO(0, newthis)
     425             :         ZEND_ARG_INFO(0, newscope)
     426             : ZEND_END_ARG_INFO()
     427             : 
     428             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_call, 0, 0, 1)
     429             :         ZEND_ARG_INFO(0, newthis)
     430             :         ZEND_ARG_VARIADIC_INFO(0, parameters)
     431             : ZEND_END_ARG_INFO()
     432             : 
     433             : static const zend_function_entry closure_functions[] = {
     434             :         ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
     435             :         ZEND_ME(Closure, bind, arginfo_closure_bind, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     436             :         ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
     437             :         ZEND_ME(Closure, call, arginfo_closure_call, ZEND_ACC_PUBLIC)
     438             :         {NULL, NULL, NULL}
     439             : };
     440             : 
     441       20423 : void zend_register_closure_ce(TSRMLS_D) /* {{{ */
     442             : {
     443             :         zend_class_entry ce;
     444             : 
     445       20423 :         INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
     446       20423 :         zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
     447       20423 :         zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
     448       20423 :         zend_ce_closure->create_object = zend_closure_new;
     449       20423 :         zend_ce_closure->serialize = zend_class_serialize_deny;
     450       20423 :         zend_ce_closure->unserialize = zend_class_unserialize_deny;
     451             : 
     452       20423 :         memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
     453       20423 :         closure_handlers.free_obj = zend_closure_free_storage;
     454       20423 :         closure_handlers.clone_obj = NULL;
     455       20423 :         closure_handlers.get_constructor = zend_closure_get_constructor;
     456       20423 :         closure_handlers.get_method = zend_closure_get_method;
     457       20423 :         closure_handlers.write_property = zend_closure_write_property;
     458       20423 :         closure_handlers.read_property = zend_closure_read_property;
     459       20423 :         closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
     460       20423 :         closure_handlers.has_property = zend_closure_has_property;
     461       20423 :         closure_handlers.unset_property = zend_closure_unset_property;
     462       20423 :         closure_handlers.compare_objects = zend_closure_compare_objects;
     463       20423 :         closure_handlers.clone_obj = zend_closure_clone;
     464       20423 :         closure_handlers.get_debug_info = zend_closure_get_debug_info;
     465       20423 :         closure_handlers.get_closure = zend_closure_get_closure;
     466       20423 :         closure_handlers.get_gc = zend_closure_get_gc;
     467       20423 : }
     468             : /* }}} */
     469             : 
     470         398 : ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zval *this_ptr TSRMLS_DC) /* {{{ */
     471             : {
     472             :         zend_closure *closure;
     473             : 
     474         398 :         object_init_ex(res, zend_ce_closure);
     475             : 
     476         398 :         closure = (zend_closure *)Z_OBJ_P(res);
     477             : 
     478         398 :         closure->func = *func;
     479         398 :         closure->func.common.prototype = NULL;
     480             : 
     481         412 :         if ((scope == NULL) && this_ptr && (Z_TYPE_P(this_ptr) != IS_UNDEF)) {
     482             :                 /* use dummy scope if we're binding an object without specifying a scope */
     483             :                 /* maybe it would be better to create one for this purpose */
     484          12 :                 scope = zend_ce_closure;
     485             :         }
     486             : 
     487         398 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     488         398 :                 if (closure->func.op_array.static_variables) {
     489         115 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     490             : 
     491         115 :                         ALLOC_HASHTABLE(closure->func.op_array.static_variables);
     492         115 :                         zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
     493         115 :                         zend_hash_apply_with_arguments(static_variables TSRMLS_CC, zval_copy_static_var, 1, closure->func.op_array.static_variables);
     494             :                 }
     495         398 :                 closure->func.op_array.run_time_cache = NULL;
     496         398 :                 (*closure->func.op_array.refcount)++;
     497             :         } else {
     498             :                 /* verify that we aren't binding internal function to a wrong scope */
     499           0 :                 if(func->common.scope != NULL) {
     500           0 :                         if(scope && !instanceof_function(scope, func->common.scope TSRMLS_CC)) {
     501           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);
     502           0 :                                 scope = NULL;
     503             :                         }
     504           0 :                         if(scope && this_ptr && (func->common.fn_flags & ZEND_ACC_STATIC) == 0 &&
     505           0 :                                         !instanceof_function(Z_OBJCE_P(this_ptr), closure->func.common.scope TSRMLS_CC)) {
     506           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);
     507           0 :                                 scope = NULL;
     508           0 :                                 this_ptr = NULL;
     509             :                         }
     510             :                 } else {
     511             :                         /* if it's a free function, we won't set scope & this since they're meaningless */
     512           0 :                         this_ptr = NULL;
     513           0 :                         scope = NULL;
     514             :                 }
     515             :         }
     516             : 
     517         398 :         ZVAL_UNDEF(&closure->this_ptr);
     518             :         /* Invariants:
     519             :          * If the closure is unscoped, it has no bound object.
     520             :          * The the closure is scoped, it's either static or it's bound */
     521         398 :         closure->func.common.scope = scope;
     522         398 :         if (scope) {
     523          93 :                 closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
     524         213 :                 if (this_ptr && Z_TYPE_P(this_ptr) == IS_OBJECT && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
     525          55 :                         ZVAL_COPY(&closure->this_ptr, this_ptr);
     526             :                 } else {
     527          38 :                         closure->func.common.fn_flags |= ZEND_ACC_STATIC;
     528             :                 }
     529             :         }
     530         398 : }
     531             : /* }}} */
     532             : 
     533             : /*
     534             :  * Local variables:
     535             :  * tab-width: 4
     536             :  * c-basic-offset: 4
     537             :  * indent-tabs-mode: t
     538             :  * End:
     539             :  */

Generated by: LCOV version 1.10

Generated at Thu, 30 Oct 2014 07:41:27 +0000 (29 hours ago)

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