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

Generated by: LTP GCOV extension version 1.5

Generated at Mon, 23 Nov 2009 17:39:26 +0000 (33 hours ago)

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