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: 171 195 87.7 %
Date: 2014-04-18 Functions: 15 20 75.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2013 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             :         HashTable     *debug_info;
      41             : } zend_closure;
      42             : 
      43             : /* non-static since it needs to be referenced */
      44             : ZEND_API zend_class_entry *zend_ce_closure;
      45             : static zend_object_handlers closure_handlers;
      46             : 
      47          15 : ZEND_METHOD(Closure, __invoke) /* {{{ */
      48             : {
      49          15 :         zend_function *func = EG(current_execute_data)->function_state.function;
      50             :         zval ***arguments;
      51          15 :         zval *closure_result_ptr = NULL;
      52             : 
      53          15 :         arguments = emalloc(sizeof(zval**) * ZEND_NUM_ARGS());
      54          15 :         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          15 :         } else if (call_user_function_ex(CG(function_table), NULL, this_ptr, &closure_result_ptr, ZEND_NUM_ARGS(), arguments, 1, NULL TSRMLS_CC) == FAILURE) {
      59           0 :                 RETVAL_FALSE;
      60          15 :         } else if (closure_result_ptr) {
      61          32 :                 if (Z_ISREF_P(closure_result_ptr) && return_value_ptr) {
      62           2 :                         if (return_value) {
      63           2 :                                 zval_ptr_dtor(&return_value);
      64             :                         }
      65           2 :                         *return_value_ptr = closure_result_ptr;
      66             :                 } else {
      67          52 :                         RETVAL_ZVAL(closure_result_ptr, 1, 1);
      68             :                 }
      69             :         }
      70          15 :         efree(arguments);
      71             : 
      72             :         /* destruct the function also, then - we have allocated it in get_method */
      73          15 :         efree(func->internal_function.function_name);
      74          15 :         efree(func);
      75          15 : }
      76             : /* }}} */
      77             : 
      78           0 : static zend_function *zend_closure_get_constructor(zval *object TSRMLS_DC) /* {{{ */
      79             : {
      80           0 :         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
      81           0 :         return NULL;
      82             : }
      83             : /* }}} */
      84             : 
      85           0 : static int zend_closure_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
      86             : {
      87           0 :         return (Z_OBJ_HANDLE_P(o1) != Z_OBJ_HANDLE_P(o2));
      88             : }
      89             : /* }}} */
      90             : 
      91          29 : ZEND_API zend_function *zend_get_closure_invoke_method(zval *obj TSRMLS_DC) /* {{{ */
      92             : {
      93          29 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
      94          29 :         zend_function *invoke = (zend_function*)emalloc(sizeof(zend_function));
      95             : 
      96          29 :         invoke->common = closure->func.common;
      97          29 :         invoke->type = ZEND_INTERNAL_FUNCTION;
      98          29 :         invoke->internal_function.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
      99          29 :         invoke->internal_function.handler = ZEND_MN(Closure___invoke);
     100          29 :         invoke->internal_function.module = 0;
     101          29 :         invoke->internal_function.scope = zend_ce_closure;
     102          29 :         invoke->internal_function.function_name = estrndup(ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1);
     103          29 :         return invoke;
     104             : }
     105             : /* }}} */
     106             : 
     107           6 : ZEND_API const zend_function *zend_get_closure_method_def(zval *obj TSRMLS_DC) /* {{{ */
     108             : {
     109           6 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
     110           6 :         return &closure->func;
     111             : }
     112             : /* }}} */
     113             : 
     114          15 : static zend_function *zend_closure_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC) /* {{{ */
     115             : {
     116             :         char *lc_name;
     117             :         ALLOCA_FLAG(use_heap)
     118             : 
     119          15 :         lc_name = do_alloca(method_len + 1, use_heap);
     120          15 :         zend_str_tolower_copy(lc_name, method_name, method_len);
     121          30 :         if ((method_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
     122          15 :                 memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
     123             :         ) {
     124          15 :                 free_alloca(lc_name, use_heap);
     125          15 :                 return zend_get_closure_invoke_method(*object_ptr TSRMLS_CC);
     126             :         }
     127           0 :         free_alloca(lc_name, use_heap);
     128           0 :         return NULL;
     129             : }
     130             : /* }}} */
     131             : 
     132           1 : static zval *zend_closure_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */
     133             : {
     134           1 :         ZEND_CLOSURE_PROPERTY_ERROR();
     135             :         Z_ADDREF(EG(uninitialized_zval));
     136           1 :         return &EG(uninitialized_zval);
     137             : }
     138             : /* }}} */
     139             : 
     140           1 : static void zend_closure_write_property(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
     141             : {
     142           1 :         ZEND_CLOSURE_PROPERTY_ERROR();
     143           0 : }
     144             : /* }}} */
     145             : 
     146           0 : static zval **zend_closure_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC) /* {{{ */
     147             : {
     148           0 :         ZEND_CLOSURE_PROPERTY_ERROR();
     149           0 :         return NULL;
     150             : }
     151             : /* }}} */
     152             : 
     153           3 : static int zend_closure_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC) /* {{{ */
     154             : {
     155           3 :         if (has_set_exists != 2) {
     156           1 :                 ZEND_CLOSURE_PROPERTY_ERROR();
     157             :         }
     158           2 :         return 0;
     159             : }
     160             : /* }}} */
     161             : 
     162           0 : static void zend_closure_unset_property(zval *object, zval *member TSRMLS_DC) /* {{{ */
     163             : {
     164           0 :         ZEND_CLOSURE_PROPERTY_ERROR();
     165           0 : }
     166             : /* }}} */
     167             : 
     168         172 : static void zend_closure_free_storage(void *object TSRMLS_DC) /* {{{ */
     169             : {
     170         172 :         zend_closure *closure = (zend_closure *)object;
     171             : 
     172         172 :         zend_object_std_dtor(&closure->std TSRMLS_CC);
     173             : 
     174         172 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     175         169 :                 zend_execute_data *ex = EG(current_execute_data);
     176         417 :                 while (ex) {
     177          80 :                         if (ex->op_array == &closure->func.op_array) {
     178           1 :                                 zend_error(E_ERROR, "Cannot destroy active lambda function");
     179             :                         }
     180          79 :                         ex = ex->prev_execute_data;
     181             :                 }
     182         168 :                 destroy_op_array(&closure->func.op_array TSRMLS_CC);
     183             :         }
     184             : 
     185         171 :         if (closure->debug_info != NULL) {
     186          12 :                 zend_hash_destroy(closure->debug_info);
     187          12 :                 efree(closure->debug_info);
     188             :         }
     189             : 
     190         171 :         efree(closure);
     191         171 : }
     192             : /* }}} */
     193             : 
     194         172 : static zend_object_value zend_closure_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
     195             : {
     196             :         zend_closure *closure;
     197             :         zend_object_value object;
     198             : 
     199         172 :         closure = emalloc(sizeof(zend_closure));
     200         172 :         memset(closure, 0, sizeof(zend_closure));
     201             : 
     202         172 :         zend_object_std_init(&closure->std, class_type TSRMLS_CC);
     203             : 
     204         172 :         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);
     205         172 :         object.handlers = &closure_handlers;
     206             : 
     207         172 :         return object;
     208             : }
     209             : /* }}} */
     210             : 
     211         305 : int zend_closure_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
     212             : {
     213             :         zend_closure *closure;
     214             : 
     215         305 :         if (Z_TYPE_P(obj) != IS_OBJECT) {
     216           0 :                 return FAILURE;
     217             :         }
     218             : 
     219         305 :         closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);
     220         305 :         *fptr_ptr = &closure->func;
     221             : 
     222         305 :         if (zobj_ptr) {
     223         305 :                 *zobj_ptr = NULL;
     224             :         }
     225         305 :         *ce_ptr = NULL;
     226         305 :         return SUCCESS;
     227             : }
     228             : /* }}} */
     229             : 
     230          19 : static HashTable *zend_closure_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
     231             : {
     232          19 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(object TSRMLS_CC);
     233             :         zval *val;
     234          19 :         struct _zend_arg_info *arg_info = closure->func.common.arg_info;
     235             : 
     236          19 :         *is_temp = 0;
     237             : 
     238          19 :         if (closure->debug_info == NULL) {
     239          12 :                 ALLOC_HASHTABLE(closure->debug_info);
     240          12 :                 zend_hash_init(closure->debug_info, 1, NULL, ZVAL_PTR_DTOR, 0);
     241             :         }
     242          19 :         if (closure->debug_info->nApplyCount == 0) {
     243          17 :                 if (closure->func.type == ZEND_USER_FUNCTION && closure->func.op_array.static_variables) {
     244           6 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     245           6 :                         MAKE_STD_ZVAL(val);
     246           6 :                         array_init(val);
     247           6 :                         zend_hash_copy(Z_ARRVAL_P(val), static_variables, (copy_ctor_func_t)zval_add_ref, NULL, sizeof(zval*));
     248           6 :                         zend_symtable_update(closure->debug_info, "static", sizeof("static"), (void *) &val, sizeof(zval *), NULL);
     249             :                 }
     250             : 
     251          17 :                 if (arg_info) {
     252           3 :                         zend_uint i, required = closure->func.common.required_num_args;
     253             : 
     254           3 :                         MAKE_STD_ZVAL(val);
     255           3 :                         array_init(val);
     256             : 
     257           7 :                         for (i = 0; i < closure->func.common.num_args; i++) {
     258             :                                 char *name, *info;
     259             :                                 int name_len, info_len;
     260           4 :                                 if (arg_info->name) {
     261           8 :                                         name_len = zend_spprintf(&name, 0, "%s$%s",
     262           4 :                                                                         arg_info->pass_by_reference ? "&" : "",
     263             :                                                                         arg_info->name);
     264             :                                 } else {
     265           0 :                                         name_len = zend_spprintf(&name, 0, "%s$param%d",
     266           0 :                                                                         arg_info->pass_by_reference ? "&" : "",
     267             :                                                                         i + 1);
     268             :                                 }
     269           4 :                                 info_len = zend_spprintf(&info, 0, "%s",
     270             :                                                                 i >= required ? "<optional>" : "<required>");
     271           4 :                                 add_assoc_stringl_ex(val, name, name_len + 1, info, info_len, 0);
     272           4 :                                 efree(name);
     273           4 :                                 arg_info++;
     274             :                         }
     275           3 :                         zend_symtable_update(closure->debug_info, "parameter", sizeof("parameter"), (void *) &val, sizeof(zval *), NULL);
     276             :                 }
     277             :         }
     278             : 
     279          19 :         return closure->debug_info;
     280             : }
     281             : /* }}} */
     282             : 
     283           5 : static HashTable *zend_closure_get_properties(zval *obj TSRMLS_DC) /* {{{ */
     284             : {
     285           5 :         zend_closure *closure = (zend_closure *)zend_object_store_get_object(obj TSRMLS_CC);    
     286             : 
     287           5 :         if (GC_G(gc_active)) {
     288           3 :                 return (closure->func.type == ZEND_USER_FUNCTION) ? closure->func.op_array.static_variables : NULL;
     289             :         }
     290             : 
     291           2 :         return closure->std.properties;
     292             : }
     293             : /* }}} */
     294             : 
     295             : /* {{{ proto Closure::__construct()
     296             :    Private constructor preventing instantiation */
     297           0 : ZEND_METHOD(Closure, __construct)
     298             : {
     299           0 :         zend_error(E_RECOVERABLE_ERROR, "Instantiation of 'Closure' is not allowed");
     300           0 : }
     301             : /* }}} */
     302             : 
     303             : static const zend_function_entry closure_functions[] = {
     304             :         ZEND_ME(Closure, __construct, NULL, ZEND_ACC_PRIVATE)
     305             :         {NULL, NULL, NULL}
     306             : };
     307             : 
     308       19341 : void zend_register_closure_ce(TSRMLS_D) /* {{{ */
     309             : {
     310             :         zend_class_entry ce;
     311             : 
     312       19341 :         INIT_CLASS_ENTRY(ce, "Closure", closure_functions);
     313       19341 :         zend_ce_closure = zend_register_internal_class(&ce TSRMLS_CC);
     314       19341 :         zend_ce_closure->ce_flags |= ZEND_ACC_FINAL_CLASS;
     315       19341 :         zend_ce_closure->create_object = zend_closure_new;
     316       19341 :         zend_ce_closure->serialize = zend_class_serialize_deny;
     317       19341 :         zend_ce_closure->unserialize = zend_class_unserialize_deny;
     318             : 
     319       19341 :         memcpy(&closure_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
     320       19341 :         closure_handlers.get_constructor = zend_closure_get_constructor;
     321       19341 :         closure_handlers.get_method = zend_closure_get_method;
     322       19341 :         closure_handlers.write_property = zend_closure_write_property;
     323       19341 :         closure_handlers.read_property = zend_closure_read_property;
     324       19341 :         closure_handlers.get_property_ptr_ptr = zend_closure_get_property_ptr_ptr;
     325       19341 :         closure_handlers.has_property = zend_closure_has_property;
     326       19341 :         closure_handlers.unset_property = zend_closure_unset_property;
     327       19341 :         closure_handlers.compare_objects = zend_closure_compare_objects;
     328       19341 :         closure_handlers.clone_obj = NULL;
     329       19341 :         closure_handlers.get_debug_info = zend_closure_get_debug_info;
     330       19341 :         closure_handlers.get_closure = zend_closure_get_closure;
     331       19341 :         closure_handlers.get_properties = zend_closure_get_properties;
     332       19341 : }
     333             : /* }}} */
     334             : 
     335          61 : static int zval_copy_static_var(zval **p TSRMLS_DC, int num_args, va_list args, zend_hash_key *key) /* {{{ */
     336             : {
     337          61 :         HashTable *target = va_arg(args, HashTable*);
     338             :         zend_bool is_ref;
     339             :         zval *tmp;
     340             : 
     341          61 :         if (Z_TYPE_PP(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) {
     342          58 :                 is_ref = Z_TYPE_PP(p) & IS_LEXICAL_REF;
     343             : 
     344          58 :                 if (!EG(active_symbol_table)) {
     345          16 :                         zend_rebuild_symbol_table(TSRMLS_C);
     346             :                 }
     347          58 :                 if (zend_hash_quick_find(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, (void **) &p) == FAILURE) {
     348           8 :                         if (is_ref) {
     349           4 :                                 ALLOC_INIT_ZVAL(tmp);
     350           4 :                                 Z_SET_ISREF_P(tmp);
     351           4 :                                 zend_hash_quick_add(EG(active_symbol_table), key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), (void**)&p);
     352             :                         } else {
     353           4 :                                 tmp = EG(uninitialized_zval_ptr);
     354           4 :                                 zend_error(E_NOTICE,"Undefined variable: %s", key->arKey);
     355             :                         }
     356             :                 } else {
     357          50 :                         if (is_ref) {
     358          64 :                                 SEPARATE_ZVAL_TO_MAKE_IS_REF(p);
     359          16 :                                 tmp = *p;
     360          68 :                         } else if (Z_ISREF_PP(p)) {
     361          10 :                                 ALLOC_INIT_ZVAL(tmp);
     362          10 :                                 *tmp = **p;
     363          10 :                                 zval_copy_ctor(tmp);
     364          10 :                                 Z_SET_REFCOUNT_P(tmp, 0);
     365          10 :                                 Z_UNSET_ISREF_P(tmp);
     366             :                         } else {
     367          24 :                                 tmp = *p;
     368             :                         }
     369             :                 }
     370             :         } else {
     371           3 :                 tmp = *p;
     372             :         }
     373          61 :         if (zend_hash_quick_add(target, key->arKey, key->nKeyLength, key->h, &tmp, sizeof(zval*), NULL) == SUCCESS) {
     374          61 :                 Z_ADDREF_P(tmp);
     375             :         }
     376          61 :         return ZEND_HASH_APPLY_KEEP;
     377             : }
     378             : /* }}} */
     379             : 
     380         169 : ZEND_API void zend_create_closure(zval *res, zend_function *func TSRMLS_DC) /* {{{ */
     381             : {
     382             :         zend_closure *closure;
     383             : 
     384         169 :         object_init_ex(res, zend_ce_closure);
     385             : 
     386         169 :         closure = (zend_closure *)zend_object_store_get_object(res TSRMLS_CC);
     387             : 
     388         169 :         closure->func = *func;
     389         169 :         closure->func.common.prototype = NULL;
     390             : 
     391         169 :         if (closure->func.type == ZEND_USER_FUNCTION) {
     392         169 :                 if (closure->func.op_array.static_variables) {
     393          55 :                         HashTable *static_variables = closure->func.op_array.static_variables;
     394             : 
     395          55 :                         ALLOC_HASHTABLE(closure->func.op_array.static_variables);
     396          55 :                         zend_hash_init(closure->func.op_array.static_variables, zend_hash_num_elements(static_variables), NULL, ZVAL_PTR_DTOR, 0);
     397          55 :                         zend_hash_apply_with_arguments(static_variables TSRMLS_CC, (apply_func_args_t)zval_copy_static_var, 1, closure->func.op_array.static_variables);
     398             :                 }
     399         169 :                 (*closure->func.op_array.refcount)++;
     400             :         }
     401             : 
     402         169 :         closure->func.common.scope = NULL;
     403         169 : }
     404             : /* }}} */
     405             : 
     406             : /*
     407             :  * Local variables:
     408             :  * tab-width: 4
     409             :  * c-basic-offset: 4
     410             :  * indent-tabs-mode: t
     411             :  * End:
     412             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:23 +0000 (5 days ago)

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