PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_3/Zend - zend_closures.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 179
Code covered: 86.6 % Executed lines: 155
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:26:55 +0000 (3 days ago)

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