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

Generated by: LCOV version 1.10

Generated at Tue, 29 Jul 2014 09:53:00 +0000 (47 hours ago)

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