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 230 85.7 %
Date: 2014-07-21 Functions: 17 22 77.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 = EG(current_execute_data)->function_state.function;
      51             :         zval ***arguments;
      52          19 :         zval *closure_result_ptr = NULL;
      53             : 
      54          19 :         arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS());
      55          19 :         if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), arguments) == FAILURE) {
      56           0 :                 efree(arguments);
      57           0 :                 zend_error(E_RECOVERABLE_ERROR, "Cannot get arguments for calling closure");
      58           0 :                 RETVAL_FALSE;
      59          19 :         } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
      60           0 :                 RETVAL_FALSE;
      61          19 :         } else if (closure_result_ptr) {
      62          19 :                 zval_ptr_dtor(&return_value);
      63          19 :                 *return_value_ptr = closure_result_ptr;
      64             :         }
      65          19 :         efree(arguments);
      66             : 
      67             :         /* destruct the function also, then - we have allocated it in get_method */
      68          19 :         efree((char*)func->internal_function.function_name);
      69          19 :         efree(func);
      70          19 : }
      71             : /* }}} */
      72             : 
      73             : /* {{{ proto Closure Closure::bind(Closure $old, object $to [, mixed $scope = "static" ] )
      74             :    Create a closure from another one and bind to another object and scope */
      75          53 : ZEND_METHOD(Closure, bind)
      76             : {
      77          53 :         zval *newthis, *zclosure, *scope_arg = NULL;
      78             :         zend_closure *closure;
      79             :         zend_class_entry *ce, **ce_p;
      80             : 
      81          53 :         if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oo!|z", &zclosure, zend_ce_closure, &newthis, &scope_arg) == FAILURE) {
      82           3 :                 RETURN_NULL();
      83             :         }
      84             : 
      85          50 :         closure = (zend_closure *)zend_object_store_get_object(zclosure TSRMLS_CC);
      86             : 
      87          50 :         if ((newthis != NULL) && (closure->func.common.fn_flags & ZEND_ACC_STATIC)) {
      88          10 :                 zend_error(E_WARNING, "Cannot bind an instance to a static closure");
      89             :         }
      90             : 
      91          50 :         if (scope_arg != NULL) { /* scope argument was given */
      92          38 :                 if (IS_ZEND_STD_OBJECT(*scope_arg)) {
      93           4 :                         ce = Z_OBJCE_P(scope_arg);
      94          30 :                 } else if (Z_TYPE_P(scope_arg) == IS_NULL) {
      95          11 :                         ce = NULL;
      96             :                 } else {
      97             :                         char *class_name;
      98             :                         int class_name_len;
      99             :                         zval tmp_zval;
     100          19 :                         INIT_ZVAL(tmp_zval);
     101             : 
     102          19 :                         if (Z_TYPE_P(scope_arg) == IS_STRING) {
     103          18 :                                 class_name = Z_STRVAL_P(scope_arg);
     104          18 :                                 class_name_len = Z_STRLEN_P(scope_arg);
     105             :                         } else {
     106           1 :                                 tmp_zval = *scope_arg;
     107             :                                 zval_copy_ctor(&tmp_zval);
     108           1 :                                 convert_to_string(&tmp_zval);
     109           1 :                                 class_name = Z_STRVAL(tmp_zval);
     110           1 :                                 class_name_len = Z_STRLEN(tmp_zval);
     111             :                         }
     112             : 
     113          29 :                         if ((class_name_len == sizeof("static") - 1) &&
     114           5 :                                 (memcmp("static", class_name, sizeof("static") - 1) == 0)) {
     115           5 :                                 ce = closure->func.common.scope;
     116             :                         }
     117          14 :                         else if (zend_lookup_class_ex(class_name, class_name_len, NULL, 1, &ce_p TSRMLS_CC) == FAILURE) {
     118           1 :                                 zend_error(E_WARNING, "Class '%s' not found", class_name);
     119             :                                 zval_dtor(&tmp_zval);
     120           1 :                                 RETURN_NULL();
     121             :                         } else {
     122          13 :                                 ce = *ce_p;
     123             :                         }
     124             :                         zval_dtor(&tmp_zval);
     125             :                 }
     126             :         } else { /* scope argument not given; do not change the scope by default */
     127          16 :                 ce = closure->func.common.scope;
     128             :         }
     129             : 
     130          49 :         zend_create_closure(return_value, &closure->func, ce, newthis TSRMLS_CC);
     131             : }
     132             : /* }}} */
     133             : 
     134           0 : static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
     135             : {
     136           0 :         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
     137           0 :         return NULL;
     138             : }
     139             : /* }}} */
     140             : 
     141           0 : static int zend_closure_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
     142             : {
     143           0 :         return (Z_OBJ_HANDLE_P(o1) != Z_OBJ_HANDLE_P(o2));
     144             : }
     145             : /* }}} */
     146             : 
     147          34 : ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {{{ */
     148             : {
     149          34 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
     150          34 :         zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
     151             : 
     152          34 :         invoke->common = closure->func.common;
     153          34 :         invoke->type = ZEND_INTERNAL_FUNCTION;
     154          34 :         invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER | (closure->func.common.fn_flags & ZEND_ACC_RETURN_REFERENCE);
     155          34 :         invoke->internal_function.handler = ZEND_MN(Closure___invoke);
     156          34 :         invoke->internal_function.module = 0;
     157          34 :         invoke->internal_function.scope = zend_ce_closure;
     158          34 :         invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
     159          34 :         return invoke;
     160             : }
     161             : /* }}} */
     162             : 
     163          23 : ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC) /* {{{ */
     164             : {
     165          23 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
     166          23 :         return &closure->func;
     167             : }
     168             : /* }}} */
     169             : 
     170           3 : ZEND_API zval* zend_get_closure_this_ptr(zval *obj TSRMLS_DC) /* {{{ */
     171             : {
     172           3 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
     173           3 :         return closure->this_ptr;
     174             : }
     175             : /* }}} */
     176             : 
     177          67 : static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */
     178             : {
     179             :         char *lc_name;
     180             :         ALLOCA_FLAG(use_heap)
     181             : 
     182          67 :         lc_name = do_alloca(method_len + 1, use_heap);
     183          67 :         zend_str_tolower_copy(lc_name, method_name, method_len);
     184          86 :         if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
     185          19 :                 memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
     186             :         ) {
     187          19 :                 free_alloca(lc_name, use_heap);
     188          19 :                 return zend_get_closure_invoke_method(*object_ptr TSRMLS_CC);
     189             :         }
     190          48 :         free_alloca(lc_name, use_heap);
     191          48 :         return std_object_handlers.get_method(object_ptr, method_name, method_len, key TSRMLS_CC);
     192             : }
     193             : /* }}} */
     194             : 
     195           1 : static zval *zend_closure_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
     196             : {
     197           1 :         ZEND_CLOSURE_PROPERTY_ERROR();
     198             :         Z_ADDREF(EG(uninitialized_zval));
     199           1 :         return &EG(uninitialized_zval);
     200             : }
     201             : /* }}} */
     202             : 
     203           1 : static void zend_closure_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
     204             : {
     205           1 :         ZEND_CLOSURE_PROPERTY_ERROR();
     206           0 : }
     207             : /* }}} */
     208             : 
     209           0 : static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
     210             : {
     211           0 :         ZEND_CLOSURE_PROPERTY_ERROR();
     212           0 :         return NULL;
     213             : }
     214             : /* }}} */
     215             : 
     216           3 : static int zend_closure_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
     217             : {
     218           3 :         if (has_set_exists != 2) {
     219           1 :                 ZEND_CLOSURE_PROPERTY_ERROR();
     220             :         }
     221           2 :         return 0;
     222             : }
     223             : /* }}} */
     224             : 
     225           0 : static void zend_closure_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
     226             : {
     227           0 :         ZEND_CLOSURE_PROPERTY_ERROR();
     228           0 : }
     229             : /* }}} */
     230             : 
     231         367 : static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */
     232             : {
     233         367 :         zend_closure *closure = (zend_closure *)object;
     234             : 
     235         367 :         zend_object_std_dtor(&closure->std TSRMLS_CC);
     236             : 
     237         367 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     238         363 :                 zend_execute_data *ex = EG(current_execute_data);
     239         892 :                 while (ex) {
     240         167 :                         if (ex->op_array == &closure->func.op_array) {
     241           1 :                                 zend_error(E_ERROR, "Cannot destroy active lambda function");
     242             :                         }
     243         166 :                         ex = ex->prev_execute_data;
     244             :                 }
     245         362 :                 destroy_op_array(&closure->func.op_array TSRMLS_CC);
     246             :         }
     247             : 
     248         366 :         if (closure->debug_info != NULL) {
     249          18 :                 zend_hash_destroy(closure->debug_info);
     250          18 :                 efree(closure->debug_info);
     251             :         }
     252             : 
     253         366 :         if (closure->this_ptr) {
     254          54 :                 zval_ptr_dtor(&closure->this_ptr);
     255             :         }
     256             : 
     257         366 :         efree(closure);
     258         366 : }
     259             : /* }}} */
     260             : 
     261         367 : static zend_object_value zend_closure_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
     262             : {
     263             :         zend_closure *closure;
     264             :         zend_object_value object;
     265             : 
     266         367 :         closure = emalloc(sizeof(zend_closure));
     267         367 :         memset(closure, 0, sizeof(zend_closure));
     268             : 
     269         367 :         zend_object_std_init(&closure->std, class_type TSRMLS_CC);
     270             : 
     271         367 :         object.handle = zend_objects_store_put(closure, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) zend_closure_free_storage, NULL TSRMLS_CC);
     272         367 :         object.handlers = &closure_handlers;
     273             : 
     274         367 :         return object;
     275             : }
     276             : /* }}} */
     277             : 
     278           2 : static zend_object_value zend_closure_clone(zval *zobject TSRMLS_DC) /* {{{ */
     279             : {
     280           2 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(zobject TSRMLS_CC);
     281             :         zval result;
     282             : 
     283           2 :         zend_create_closure(&result, &closure->func, closure->func.common.scope, closure->this_ptr TSRMLS_CC);
     284           2 :         return Z_OBJVAL(result);
     285             : }
     286             : /* }}} */
     287             : 
     288         632 : int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
     289             : {
     290             :         zend_closure *closure;
     291             : 
     292         632 :         if (Z_TYPE_P(obj) != IS_OBJECT) {
     293           0 :                 return FAILURE;
     294             :         }
     295             : 
     296         632 :         closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
     297         632 :         *fptr_ptr = &closure->func;
     298             : 
     299         632 :         if (closure->this_ptr) {
     300          59 :                 if (zobj_ptr) {
     301          59 :                         *zobj_ptr = closure->this_ptr;
     302             :                 }
     303          59 :                 *ce_ptr = Z_OBJCE_P(closure->this_ptr);
     304             :         } else {
     305         573 :                 if (zobj_ptr) {
     306         573 :                         *zobj_ptr = NULL;
     307             :                 }
     308         573 :                 *ce_ptr = closure->func.common.scope;
     309             :         }
     310         632 :         return SUCCESS;
     311             : }
     312             : /* }}} */
     313             : 
     314          25 : static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
     315             : {
     316          25 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
     317             :         zval *val;
     318          25 :         struct _zend_arg_info *arg_info = closure->func.common.arg_info;
     319             : 
     320          25 :         *is_temp = 0;
     321             : 
     322          25 :         if (closure->debug_info == NULL) {
     323          18 :                 ALLOC_HASHTABLE(closure->debug_info);
     324          18 :                 zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
     325             :         }
     326          25 :         if (closure->debug_info->nApplyCount == 0) {
     327          23 :                 if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
     328           6 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     329           6 :                         MAKE_STD_ZVAL(val);
     330           6 :                         array_init(val);
     331           6 :                         zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
     332           6 :                         zend_hash_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
     333             :                 }
     334             : 
     335          23 :                 if (closure->this_ptr) {
     336           3 :                         Z_ADDREF_P(closure->this_ptr);
     337           3 :                         zend_symtable_update(closure->debug_info, "this", sizeof("this"), (void *) &closure->this_ptr, sizeof(zval *), NULL);
     338             :                 }
     339             : 
     340          23 :                 if (arg_info) {
     341           4 :                         zend_uint i, required = closure->func.common.required_num_args;
     342             : 
     343           4 :                         MAKE_STD_ZVAL(val);
     344           4 :                         array_init(val);
     345             : 
     346          10 :                         for (i = 0; i < closure->func.common.num_args; i++) {
     347             :                                 char *name, *info;
     348             :                                 int name_len, info_len;
     349           6 :                                 if (arg_info->name) {
     350          12 :                                         name_len = zend_spprintf(&name, 0, "%s$%s",
     351           6 :                                                                         arg_info->pass_by_reference ? "&" : "",
     352             :                                                                         arg_info->name);
     353             :                                 } else {
     354           0 :                                         name_len = zend_spprintf(&name, 0, "%s$param%d",
     355           0 :                                                                         arg_info->pass_by_reference ? "&" : "",
     356             :                                                                         i + 1);
     357             :                                 }
     358           6 :                                 info_len = zend_spprintf(&info, 0, "%s",
     359             :                                                                 i >= required ? "<optional>" : "<required>");
     360           6 :                                 add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
     361           6 :                                 efree(name);
     362           6 :                                 arg_info++;
     363             :                         }
     364           4 :                         zend_hash_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
     365             :                 }
     366             :         }
     367             : 
     368          25 :         return closure->debug_info;
     369             : }
     370             : /* }}} */
     371             : 
     372           6 : static HashTable *zend_closure_get_gc(zval *obj, zval ***table, int *n TSRMLS_DC) /* {{{ */
     373             : {
     374           6 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
     375             : 
     376           6 :         *table = closure->this_ptr ? &closure->this_ptr : NULL;
     377           6 :         *n = closure->this_ptr ? 1 : 0;
     378           6 :         return (closure->func.type == ZEND_USER_FUNCTION) ?
     379             :                 closure->func.op_array.static_variables : NULL;
     380             : }
     381             : /* }}} */
     382             : 
     383             : /* {{{ proto Closure::__construct()
     384             :    Private constructor preventing instantiation */
     385           0 : ZEND_METHOD(Closure, __construct)
     386             : {
     387           0 :         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
     388           0 : }
     389             : /* }}} */
     390             : 
     391             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bindto, 0, 0, 1)
     392             :         ZEND_ARG_INFO(0, newthis)
     393             :         ZEND_ARG_INFO(0, newscope)
     394             : ZEND_END_ARG_INFO()
     395             : 
     396             : ZEND_BEGIN_ARG_INFO_EX(arginfo_closure_bind, 0, 0, 2)
     397             :         ZEND_ARG_INFO(0, closure)
     398             :         ZEND_ARG_INFO(0, newthis)
     399             :         ZEND_ARG_INFO(0, newscope)
     400             : ZEND_END_ARG_INFO()
     401             : 
     402             : static const zend_function_entry closure_functions[] = {
     403             :         ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
     404             :         ZEND_ME(Closure, bind, arginfo_closure_bind, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
     405             :         ZEND_MALIAS(Closure, bindTo, bind, arginfo_closure_bindto, ZEND_ACC_PUBLIC)
     406             :         {NULL, NULL, NULL}
     407             : };
     408             : 
     409       21257 : void zend_register_closure_ce(TSRMLS_D) /* {{{ */
     410             : {
     411             :         zend_class_entry ce;
     412             : 
     413       21257 :         INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
     414       21257 :         zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
     415       21257 :         zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
     416       21257 :         zend_ce_closure->create_object = zend_closure_new;
     417       21257 :         zend_ce_closure->serialize = zend_class_serialize_deny;
     418       21257 :         zend_ce_closure->unserialize = zend_class_unserialize_deny;
     419             : 
     420       21257 :         memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
     421       21257 :         closure_handlers.get_constructor = zend_closure_get_constructor;
     422       21257 :         closure_handlers.get_method = zend_closure_get_method;
     423       21257 :         closure_handlers.write_property = zend_closure_write_property;
     424       21257 :         closure_handlers.read_property = zend_closure_read_property;
     425       21257 :         closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
     426       21257 :         closure_handlers.has_property = zend_closure_has_property;
     427       21257 :         closure_handlers.unset_property = zend_closure_unset_property;
     428       21257 :         closure_handlers.compare_objects = zend_closure_compare_objects;
     429       21257 :         closure_handlers.clone_obj = zend_closure_clone;
     430       21257 :         closure_handlers.get_debug_info = zend_closure_get_debug_info;
     431       21257 :         closure_handlers.get_closure = zend_closure_get_closure;
     432       21257 :         closure_handlers.get_gc = zend_closure_get_gc;
     433       21257 : }
     434             : /* }}} */
     435             : 
     436         363 : ZEND_API void zend_create_closure(zval *res, zend_function *func, zend_class_entry *scope, zval *this_ptr TSRMLS_DC) /* {{{ */
     437             : {
     438             :         zend_closure *closure;
     439             : 
     440         363 :         object_init_ex(res, zend_ce_closure);
     441             : 
     442         363 :         closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);
     443             : 
     444         363 :         closure->func = *func;
     445         363 :         closure->func.common.prototype = NULL;
     446             : 
     447         363 :         if ((scope == NULL) && (this_ptr != NULL)) {
     448             :                 /* use dummy scope if we're binding an object without specifying a scope */
     449             :                 /* maybe it would be better to create one for this purpose */
     450          12 :                 scope = zend_ce_closure;
     451             :         }
     452             : 
     453         363 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     454         363 :                 if (closure->func.op_array.static_variables) {
     455         104 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     456             : 
     457         104 :                         ALLOC_HASHTABLE(closure->func.op_array.static_variables);
     458         104 :                         zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
     459         104 :                         zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, closure->func.op_array.static_variables);
     460             :                 }
     461         363 :                 closure->func.op_array.run_time_cache = NULL;
     462         363 :                 (*closure->func.op_array.refcount)++;
     463             :         } else {
     464             :                 /* verify that we aren't binding internal function to a wrong scope */
     465           0 :                 if(func->common.scope != NULL) {
     466           0 :                         if(scope && !instanceof_function(scope, func->common.scope TSRMLS_CC)) {
     467           0 :                                 zend_error(E_WARNING, "Cannot bind function %s::%s to scope class %s", func->common.scope->name, func->common.function_name, scope->name);
     468           0 :                                 scope = NULL;
     469             :                         }
     470           0 :                         if(scope && this_ptr && (func->common.fn_flags & ZEND_ACC_STATIC) == 0 &&
     471           0 :                                         !instanceof_function(Z_OBJCE_P(this_ptr), closure->func.common.scope TSRMLS_CC)) {
     472           0 :                                 zend_error(E_WARNING, "Cannot bind function %s::%s to object of class %s", func->common.scope->name, func->common.function_name, Z_OBJCE_P(this_ptr)->name);
     473           0 :                                 scope = NULL;
     474           0 :                                 this_ptr = NULL;
     475             :                         }
     476             :                 } else {
     477             :                         /* if it's a free function, we won't set scope & this since they're meaningless */
     478           0 :                         this_ptr = NULL;
     479           0 :                         scope = NULL;
     480             :                 }
     481             :         }
     482             : 
     483         363 :         closure->this_ptr = NULL;
     484             :         /* Invariants:
     485             :          * If the closure is unscoped, it has no bound object.
     486             :          * The the closure is scoped, it's either static or it's bound */
     487         363 :         closure->func.common.scope = scope;
     488         363 :         if (scope) {
     489          92 :                 closure->func.common.fn_flags |= ZEND_ACC_PUBLIC;
     490         146 :                 if (this_ptr && (closure->func.common.fn_flags & ZEND_ACC_STATIC) == 0) {
     491          54 :                         closure->this_ptr = this_ptr;
     492             :                         Z_ADDREF_P(this_ptr);
     493             :                 } else {
     494          38 :                         closure->func.common.fn_flags |= ZEND_ACC_STATIC;
     495             :                 }
     496             :         }
     497         363 : }
     498             : /* }}} */
     499             : 
     500             : /*
     501             :  * Local variables:
     502             :  * tab-width: 4
     503             :  * c-basic-offset: 4
     504             :  * indent-tabs-mode: t
     505             :  * End:
     506             :  */

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:06 +0000 (11 days ago)

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