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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:10 +0000 (7 days ago)

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