LTP GCOV extension - code coverage report
Current view: directory - Zend - zend_object_handlers.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 510
Code covered: 29.6 % Executed lines: 151
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | Zend Engine                                                          |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1998-2007 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: Andi Gutmans <andi@zend.com>                                |
      16                 :    |          Zeev Suraski <zeev@zend.com>                                |
      17                 :    +----------------------------------------------------------------------+
      18                 : */
      19                 : 
      20                 : /* $Id: zend_object_handlers.c,v 1.135.2.6.2.20 2007/03/23 17:16:55 stas Exp $ */
      21                 : 
      22                 : #include "zend.h"
      23                 : #include "zend_globals.h"
      24                 : #include "zend_variables.h"
      25                 : #include "zend_API.h"
      26                 : #include "zend_objects.h"
      27                 : #include "zend_objects_API.h"
      28                 : #include "zend_object_handlers.h"
      29                 : #include "zend_interfaces.h"
      30                 : 
      31                 : #define DEBUG_OBJECT_HANDLERS 0
      32                 : 
      33                 : #define Z_OBJ_P(zval_p) zend_objects_get_address(zval_p TSRMLS_CC)
      34                 : 
      35                 : /*
      36                 :   __X accessors explanation:
      37                 : 
      38                 :   if we have __get and property that is not part of the properties array is
      39                 :   requested, we call __get handler. If it fails, we return uninitialized.
      40                 : 
      41                 :   if we have __set and property that is not part of the properties array is
      42                 :   set, we call __set handler. If it fails, we do not change the array.
      43                 : 
      44                 :   for both handlers above, when we are inside __get/__set, no further calls for
      45                 :   __get/__set for this property of this object will be made, to prevent endless 
      46                 :   recursion and enable accessors to change properties array.
      47                 : 
      48                 :   if we have __call and method which is not part of the class function table is
      49                 :   called, we cal __call handler.
      50                 : */
      51                 : 
      52                 : static HashTable *zend_std_get_properties(zval *object TSRMLS_DC)
      53              85 : {
      54                 :         zend_object *zobj;
      55              85 :         zobj = Z_OBJ_P(object);
      56                 : #if DEBUG_OBJECT_HANDLERS
      57                 :         fprintf(stderr, "Read object #%d properties (%d)\n", Z_OBJ_HANDLE_P(object), zend_hash_num_elements(zobj->properties));
      58                 : #endif
      59              85 :         return zobj->properties;
      60                 : }
      61                 : 
      62                 : static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC)
      63               0 : {
      64               0 :         zval *retval = NULL;
      65               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
      66                 : 
      67                 :         /* __get handler is called with one argument:
      68                 :               property name
      69                 : 
      70                 :            it should return whether the call was successfull or not
      71                 :         */
      72                 : 
      73               0 :         SEPARATE_ARG_IF_REF(member);
      74                 : 
      75               0 :         zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
      76                 : 
      77               0 :         zval_ptr_dtor(&member);
      78                 : 
      79               0 :         if (retval) {
      80               0 :                 retval->refcount--;
      81                 :         }
      82                 : 
      83               0 :         return retval;
      84                 : }
      85                 : 
      86                 : static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC)
      87               0 : {
      88               0 :         zval *retval = NULL;
      89                 :         int result;
      90               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
      91                 : 
      92               0 :         SEPARATE_ARG_IF_REF(member);
      93               0 :         value->refcount++;
      94                 : 
      95                 :         /* __set handler is called with two arguments:
      96                 :              property name
      97                 :              value to be set
      98                 : 
      99                 :            it should return whether the call was successfull or not
     100                 :         */
     101               0 :         zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
     102                 : 
     103               0 :         zval_ptr_dtor(&member);
     104               0 :         zval_ptr_dtor(&value);
     105                 : 
     106               0 :         if (retval) {
     107               0 :                 result = i_zend_is_true(retval) ? SUCCESS : FAILURE;
     108               0 :                 zval_ptr_dtor(&retval);
     109               0 :                 return result;
     110                 :         } else {
     111               0 :                 return FAILURE;
     112                 :         }
     113                 : }
     114                 : 
     115                 : static void zend_std_call_unsetter(zval *object, zval *member TSRMLS_DC)
     116               0 : {
     117               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
     118                 : 
     119                 :         /* __unset handler is called with one argument:
     120                 :               property name
     121                 :         */
     122                 : 
     123               0 :         SEPARATE_ARG_IF_REF(member);
     124                 : 
     125               0 :         zend_call_method_with_1_params(&object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member);
     126                 : 
     127               0 :         zval_ptr_dtor(&member);
     128               0 : }
     129                 : 
     130                 : static zval *zend_std_call_issetter(zval *object, zval *member TSRMLS_DC)
     131               0 : {
     132               0 :         zval *retval = NULL;
     133               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
     134                 : 
     135                 :         /* __isset handler is called with one argument:
     136                 :               property name
     137                 : 
     138                 :            it should return whether the property is set or not
     139                 :         */
     140                 : 
     141               0 :         SEPARATE_ARG_IF_REF(member);
     142                 : 
     143               0 :         zend_call_method_with_1_params(&object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, &retval, member);
     144                 : 
     145               0 :         zval_ptr_dtor(&member);
     146                 : 
     147               0 :         return retval;
     148                 : }
     149                 : 
     150                 : static int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC)
     151            1883 : {
     152            1883 :         switch (property_info->flags & ZEND_ACC_PPP_MASK) {
     153                 :                 case ZEND_ACC_PUBLIC:
     154             119 :                         return 1;
     155                 :                 case ZEND_ACC_PROTECTED:
     156             168 :                         return zend_check_protected(property_info->ce, EG(scope));
     157                 :                 case ZEND_ACC_PRIVATE:
     158            1596 :                         if (ce==EG(scope) && EG(scope)) {
     159            1596 :                                 return 1;
     160                 :                         } else {
     161               0 :                                 return 0;
     162                 :                         }
     163                 :                         break;
     164                 :         }
     165               0 :         return 0;
     166                 : }
     167                 : 
     168                 : static inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class)
     169             150 : {
     170             150 :         child_class = child_class->parent;
     171             352 :         while (child_class) {
     172             148 :                 if (child_class == parent_class) {
     173              96 :                         return 1;
     174                 :                 }
     175              52 :                 child_class = child_class->parent;
     176                 :         }
     177                 : 
     178              54 :         return 0;
     179                 : }
     180                 : 
     181                 : ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC)
     182            1924 : {
     183            1924 :         zend_property_info *property_info = NULL;
     184                 :         zend_property_info *scope_property_info;
     185            1924 :         zend_bool denied_access = 0;
     186                 :         ulong h;
     187                 : 
     188            1924 :         if (Z_STRVAL_P(member)[0] == '\0') {
     189               0 :                 if (!silent) {
     190               0 :                         if (Z_STRLEN_P(member) == 0) {
     191               0 :                                 zend_error(E_ERROR, "Cannot access empty property");
     192                 :                         } else {
     193               0 :                                 zend_error(E_ERROR, "Cannot access property started with '\\0'");
     194                 :                         }
     195                 :                 }
     196               0 :                 return NULL;
     197                 :         }
     198            1924 :         h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
     199            1924 :         if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) {
     200            1870 :                 if(property_info->flags & ZEND_ACC_SHADOW) {
     201                 :                         /* if it's a shadow - go to access it's private */
     202              96 :                         property_info = NULL;
     203                 :                 } else {
     204            1774 :                         if (zend_verify_property_access(property_info, ce TSRMLS_CC)) {
     205            1774 :                                 if (property_info->flags & ZEND_ACC_CHANGED
     206                 :                                         && !(property_info->flags & ZEND_ACC_PRIVATE)) {
     207                 :                                         /* We still need to make sure that we're not in a context
     208                 :                                          * where the right property is a different 'statically linked' private
     209                 :                                          * continue checking below...
     210                 :                                          */
     211                 :                                 } else {
     212            1774 :                                         if (!silent && (property_info->flags & ZEND_ACC_STATIC)) {
     213               0 :                                                 zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));
     214                 :                                         }
     215            1774 :                                         return property_info;
     216                 :                                 }
     217                 :                         } else {
     218                 :                                 /* Try to look in the scope instead */
     219               0 :                                 denied_access = 1;
     220                 :                         }
     221                 :                 }
     222                 :         }
     223             150 :         if (EG(scope) != ce
     224                 :                 && is_derived_class(ce, EG(scope))
     225                 :                 && EG(scope)
     226                 :                 && zend_hash_quick_find(&EG(scope)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS
     227                 :                 && scope_property_info->flags & ZEND_ACC_PRIVATE) {
     228              96 :                 return scope_property_info;
     229              54 :         } else if (property_info) {
     230               0 :                 if (denied_access) {
     231                 :                         /* Information was available, but we were denied access.  Error out. */
     232               0 :                         if (silent) {
     233               0 :                                 return NULL;
     234                 :                         }
     235               0 :                         zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, Z_STRVAL_P(member));
     236                 :                 } else {
     237                 :                         /* fall through, return property_info... */
     238                 :                 }
     239                 :         } else {
     240              54 :                 EG(std_property_info).flags = ZEND_ACC_PUBLIC;
     241              54 :                 EG(std_property_info).name = Z_STRVAL_P(member);
     242              54 :                 EG(std_property_info).name_length = Z_STRLEN_P(member);
     243              54 :                 EG(std_property_info).h = h;
     244              54 :                 EG(std_property_info).ce = ce;
     245              54 :                 property_info = &EG(std_property_info);
     246                 :         }
     247              54 :         return property_info;
     248                 : }
     249                 : 
     250                 : 
     251                 : ZEND_API int zend_check_property_access(zend_object *zobj, char *prop_info_name, int prop_info_name_len TSRMLS_DC)
     252               4 : {
     253                 :         zend_property_info *property_info;
     254                 :         char *class_name, *prop_name;
     255                 :         zval member;
     256                 : 
     257               4 :         zend_unmangle_property_name(prop_info_name, prop_info_name_len, &class_name, &prop_name);
     258               4 :         ZVAL_STRING(&member, prop_name, 0);
     259               4 :         property_info = zend_get_property_info(zobj->ce, &member, 1 TSRMLS_CC);
     260               4 :         if (!property_info) {
     261               0 :                 return FAILURE;
     262                 :         }
     263               4 :         if (prop_info_name[0] == '\0' && prop_info_name[1] != '*') {
     264               0 :                 if (!(property_info->flags & ZEND_ACC_PRIVATE)) {
     265                 :                         /* we we're looking for a private prop but found a non private one of the same name */
     266               0 :                         return FAILURE;
     267               0 :                 } else if (strcmp(prop_info_name+1, property_info->name+1)) {
     268                 :                         /* we we're looking for a private prop but found a private one of the same name but another class */
     269               0 :                         return FAILURE;
     270                 :                 }
     271                 :         }
     272               4 :         return zend_verify_property_access(property_info, zobj->ce TSRMLS_CC) ? SUCCESS : FAILURE;
     273                 : }
     274                 : 
     275                 : static int zend_get_property_guard(zend_object *zobj, zend_property_info *property_info, zval *member, zend_guard **pguard)
     276               0 : {
     277                 :         zend_property_info info;
     278                 :         zend_guard stub;
     279                 : 
     280               0 :         if (!property_info) {
     281               0 :                 property_info = &info;
     282               0 :                 info.name = Z_STRVAL_P(member);
     283               0 :                 info.name_length = Z_STRLEN_P(member);
     284               0 :                 info.h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
     285                 :         }
     286               0 :         if (!zobj->guards) {
     287               0 :                 ALLOC_HASHTABLE(zobj->guards);
     288               0 :                 zend_hash_init(zobj->guards, 0, NULL, NULL, 0);
     289               0 :         } else if (zend_hash_quick_find(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) {
     290               0 :                 return SUCCESS;
     291                 :         }
     292               0 :         stub.in_get = 0;
     293               0 :         stub.in_set = 0;
     294               0 :         stub.in_unset = 0;
     295               0 :         stub.in_isset = 0;
     296               0 :         return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
     297                 : }
     298                 : 
     299                 : zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
     300            1098 : {
     301                 :         zend_object *zobj;
     302            1098 :         zval *tmp_member = NULL;
     303                 :         zval **retval;
     304            1098 :         zval *rv = NULL;
     305                 :         zend_property_info *property_info;
     306                 :         int silent;
     307                 : 
     308            1098 :         silent = (type == BP_VAR_IS);
     309            1098 :         zobj = Z_OBJ_P(object);
     310                 : 
     311            1098 :         if (member->type != IS_STRING) {
     312               0 :                 ALLOC_ZVAL(tmp_member);
     313               0 :                 *tmp_member = *member;
     314               0 :                 INIT_PZVAL(tmp_member);
     315               0 :                 zval_copy_ctor(tmp_member);
     316               0 :                 convert_to_string(tmp_member);
     317               0 :                 member = tmp_member;
     318                 :         }
     319                 : 
     320                 : #if DEBUG_OBJECT_HANDLERS
     321                 :         fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
     322                 : #endif                  
     323                 : 
     324                 :         /* make zend_get_property_info silent if we have getter - we may want to use it */
     325            1098 :         property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC);
     326                 : 
     327            1098 :         if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) {
     328                 :                 zend_guard *guard;
     329                 : 
     330               0 :                 if (zobj->ce->__get &&
     331                 :                     zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
     332                 :                     !guard->in_get) {
     333                 :                         /* have getter - try with it! */
     334               0 :                         guard->in_get = 1; /* prevent circular getting */
     335               0 :                         rv = zend_std_call_getter(object, member TSRMLS_CC);
     336               0 :                         guard->in_get = 0;
     337                 : 
     338               0 :                         if (rv) {
     339               0 :                                 retval = &rv;
     340               0 :                                 if (!rv->is_ref &&
     341                 :                                     (type == BP_VAR_W || type == BP_VAR_RW  || type == BP_VAR_UNSET)) {
     342               0 :                                         if (rv->refcount > 0) {
     343               0 :                                                 zval *tmp = rv;
     344                 : 
     345               0 :                                                 ALLOC_ZVAL(rv);
     346               0 :                                                 *rv = *tmp;
     347               0 :                                                 zval_copy_ctor(rv);
     348               0 :                                                 rv->is_ref = 0;
     349               0 :                                                 rv->refcount = 0;
     350                 :                                         }
     351               0 :                                         if (Z_TYPE_P(rv) != IS_OBJECT) {
     352               0 :                                                 zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", zobj->ce->name, Z_STRVAL_P(member));
     353                 :                                         }
     354                 :                                 }
     355                 :                         } else {
     356               0 :                                 retval = &EG(uninitialized_zval_ptr);
     357                 :                         }
     358                 :                 } else {
     359               0 :                         if (!silent) {
     360               0 :                                 zend_error(E_NOTICE,"Undefined property:  %s::$%s", zobj->ce->name, Z_STRVAL_P(member));
     361                 :                         }
     362               0 :                         retval = &EG(uninitialized_zval_ptr);
     363                 :                 }
     364                 :         }
     365            1098 :         if (tmp_member) {
     366               0 :                 (*retval)->refcount++;
     367               0 :                 zval_ptr_dtor(&tmp_member);
     368               0 :                 (*retval)->refcount--;
     369                 :         }
     370            1098 :         return *retval;
     371                 : }
     372                 : 
     373                 : 
     374                 : static void zend_std_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
     375             720 : {
     376                 :         zend_object *zobj;
     377             720 :         zval *tmp_member = NULL;
     378                 :         zval **variable_ptr;
     379                 :         zend_property_info *property_info;
     380                 : 
     381             720 :         zobj = Z_OBJ_P(object);
     382                 : 
     383             720 :         if (member->type != IS_STRING) {
     384               0 :                 ALLOC_ZVAL(tmp_member);
     385               0 :                 *tmp_member = *member;
     386               0 :                 INIT_PZVAL(tmp_member);
     387               0 :                 zval_copy_ctor(tmp_member);
     388               0 :                 convert_to_string(tmp_member);
     389               0 :                 member = tmp_member;
     390                 :         }
     391                 : 
     392             720 :         property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__set != NULL) TSRMLS_CC);
     393                 : 
     394            1434 :         if (property_info && zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS) {
     395                 :                 /* if we already have this value there, we don't actually need to do anything */
     396             714 :                 if (*variable_ptr != value) {
     397                 :                         /* if we are assigning reference, we shouldn't move it, but instead assign variable
     398                 :                            to the same pointer */
     399             714 :                         if (PZVAL_IS_REF(*variable_ptr)) {
     400               0 :                                 zval garbage = **variable_ptr; /* old value should be destroyed */
     401                 : 
     402                 :                                 /* To check: can't *variable_ptr be some system variable like error_zval here? */
     403               0 :                                 (*variable_ptr)->type = value->type;
     404               0 :                                 (*variable_ptr)->value = value->value;
     405               0 :                                 if (value->refcount>0) {
     406               0 :                                         zval_copy_ctor(*variable_ptr);
     407                 :                                 }
     408               0 :                                 zval_dtor(&garbage);
     409                 :                         } else {
     410             714 :                                 zval *garbage = *variable_ptr;
     411                 : 
     412                 :                                 /* if we assign referenced variable, we should separate it */
     413             714 :                                 value->refcount++;
     414             714 :                                 if (PZVAL_IS_REF(value)) {
     415               0 :                                         SEPARATE_ZVAL(&value);
     416                 :                                 }
     417             714 :                                 *variable_ptr = value;
     418             714 :                                 zval_ptr_dtor(&garbage);
     419                 :                         }
     420                 :                 }
     421                 :         } else {
     422               6 :                 int setter_done = 0;
     423                 :                 zend_guard *guard;
     424                 : 
     425               6 :                 if (zobj->ce->__set &&
     426                 :                     zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
     427                 :                     !guard->in_set) {
     428               0 :                         guard->in_set = 1; /* prevent circular setting */
     429               0 :                         if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) {
     430                 :                                 /* for now, just ignore it - __set should take care of warnings, etc. */
     431                 :                         }
     432               0 :                         setter_done = 1;
     433               0 :                         guard->in_set = 0;
     434                 :                 }
     435               6 :                 if (!setter_done && property_info) {
     436                 :                         zval **foo;
     437                 : 
     438                 :                         /* if we assign referenced variable, we should separate it */
     439               6 :                         value->refcount++;
     440               6 :                         if (PZVAL_IS_REF(value)) {
     441               0 :                                 SEPARATE_ZVAL(&value);
     442                 :                         }
     443               6 :                         zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void **) &foo);
     444                 :                 }
     445                 :         }
     446                 : 
     447             720 :         if (tmp_member) {
     448               0 :                 zval_ptr_dtor(&tmp_member);
     449                 :         }
     450             720 : }
     451                 : 
     452                 : zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
     453               0 : {
     454               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
     455                 :         zval *retval;
     456                 : 
     457               0 :         if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
     458               0 :                 if(offset == NULL) {
     459                 :                         /* [] construct */
     460               0 :                         ALLOC_INIT_ZVAL(offset);
     461                 :                 } else {
     462               0 :                         SEPARATE_ARG_IF_REF(offset);
     463                 :                 }
     464               0 :                 zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
     465                 : 
     466               0 :                 zval_ptr_dtor(&offset);
     467                 : 
     468               0 :                 if (!retval) {
     469               0 :                         if (!EG(exception)) {
     470               0 :                                 zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
     471                 :                         }
     472               0 :                         return 0;
     473                 :                 }
     474                 : 
     475                 :                 /* Undo PZVAL_LOCK() */
     476               0 :                 retval->refcount--;
     477                 : 
     478               0 :                 return retval;
     479                 :         } else {
     480               0 :                 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
     481               0 :                 return 0;
     482                 :         }
     483                 : }
     484                 : 
     485                 : 
     486                 : static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
     487               0 : {
     488               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
     489                 : 
     490               0 :         if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
     491               0 :                 if (!offset) {
     492               0 :                         ALLOC_INIT_ZVAL(offset);
     493                 :                 } else {
     494               0 :                         SEPARATE_ARG_IF_REF(offset);
     495                 :                 }
     496               0 :                 zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value);
     497               0 :                 zval_ptr_dtor(&offset);
     498                 :         } else {
     499               0 :                 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
     500                 :         }
     501               0 : }
     502                 : 
     503                 : 
     504                 : static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
     505               0 : {
     506               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
     507                 :         zval *retval;
     508                 :         int result;
     509                 : 
     510               0 :         if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
     511               0 :                 SEPARATE_ARG_IF_REF(offset);
     512               0 :                 zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
     513               0 :                 if (retval) {
     514               0 :                         result = i_zend_is_true(retval);
     515               0 :                         zval_ptr_dtor(&retval);
     516               0 :                         if (check_empty && result && !EG(exception)) {
     517               0 :                                 zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
     518               0 :                                 if (retval) {
     519               0 :                                         result = i_zend_is_true(retval);
     520               0 :                                         zval_ptr_dtor(&retval);
     521                 :                                 }
     522                 :                         }
     523                 :                 } else {
     524               0 :                         result = 0;
     525                 :                 }
     526               0 :                 zval_ptr_dtor(&offset);
     527                 :         } else {
     528               0 :                 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
     529               0 :                 return 0;
     530                 :         }
     531               0 :         return result;
     532                 : }
     533                 : 
     534                 : 
     535                 : static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member TSRMLS_DC)
     536             100 : {
     537                 :         zend_object *zobj;
     538                 :         zval tmp_member;
     539                 :         zval **retval;
     540                 :         zend_property_info *property_info;
     541                 : 
     542             100 :         zobj = Z_OBJ_P(object);
     543                 : 
     544             100 :         if (member->type != IS_STRING) {
     545               0 :                 tmp_member = *member;
     546               0 :                 zval_copy_ctor(&tmp_member);
     547               0 :                 convert_to_string(&tmp_member);
     548               0 :                 member = &tmp_member;
     549                 :         }
     550                 : 
     551                 : #if DEBUG_OBJECT_HANDLERS
     552                 :         fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
     553                 : #endif
     554                 : 
     555             100 :         property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__get != NULL) TSRMLS_CC);
     556                 : 
     557             100 :         if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE) {
     558                 :                 zval *new_zval;
     559                 :                 zend_guard *guard;
     560                 : 
     561               0 :                 if (!zobj->ce->__get ||
     562                 :                     zend_get_property_guard(zobj, property_info, member, &guard) != SUCCESS ||
     563                 :                     guard->in_get) {
     564                 :                         /* we don't have access controls - will just add it */
     565               0 :                         new_zval = &EG(uninitialized_zval);
     566                 : 
     567                 : /*                      zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */
     568               0 :                         new_zval->refcount++;
     569               0 :                         zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval);
     570                 :                 } else {
     571                 :                         /* we do have getter - fail and let it try again with usual get/set */
     572               0 :                         retval = NULL;
     573                 :                 }
     574                 :         }
     575             100 :         if (member == &tmp_member) {
     576               0 :                 zval_dtor(member);
     577                 :         }
     578             100 :         return retval;
     579                 : }
     580                 : 
     581                 : 
     582                 : static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
     583               0 : {
     584                 :         zend_object *zobj;
     585               0 :         zval *tmp_member = NULL;
     586                 :         zend_property_info *property_info;
     587                 : 
     588               0 :         zobj = Z_OBJ_P(object);
     589                 : 
     590               0 :         if (member->type != IS_STRING) {
     591               0 :                 ALLOC_ZVAL(tmp_member);
     592               0 :                 *tmp_member = *member;
     593               0 :                 INIT_PZVAL(tmp_member);
     594               0 :                 zval_copy_ctor(tmp_member);
     595               0 :                 convert_to_string(tmp_member);
     596               0 :                 member = tmp_member;
     597                 :         }
     598                 : 
     599               0 :         property_info = zend_get_property_info(zobj->ce, member, (zobj->ce->__unset != NULL) TSRMLS_CC);
     600                 : 
     601               0 :         if (!property_info || zend_hash_del(zobj->properties, property_info->name, property_info->name_length+1) == FAILURE) {
     602                 :                 zend_guard *guard;
     603                 : 
     604               0 :                 if (zobj->ce->__unset &&
     605                 :                     zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
     606                 :                     !guard->in_unset) {
     607                 :                         /* have unseter - try with it! */
     608               0 :                         guard->in_unset = 1; /* prevent circular unsetting */
     609               0 :                         zend_std_call_unsetter(object, member TSRMLS_CC);
     610               0 :                         guard->in_unset = 0;
     611                 :                 }
     612                 :         }
     613                 : 
     614               0 :         if (tmp_member) {
     615               0 :                 zval_ptr_dtor(&tmp_member);
     616                 :         }
     617               0 : }
     618                 : 
     619                 : 
     620                 : static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC)
     621               0 : {
     622               0 :         zend_class_entry *ce = Z_OBJCE_P(object);
     623                 : 
     624               0 :         if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
     625               0 :                 SEPARATE_ARG_IF_REF(offset);
     626               0 :                 zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", NULL, offset);
     627               0 :                 zval_ptr_dtor(&offset);
     628                 :         } else {
     629               0 :                 zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
     630                 :         }
     631               0 : }
     632                 : 
     633                 : 
     634                 : ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS)
     635               0 : {
     636               0 :         zend_internal_function *func = (zend_internal_function *)EG(function_state_ptr)->function;
     637                 :         zval *method_name_ptr, *method_args_ptr;
     638               0 :         zval *method_result_ptr = NULL;
     639               0 :         zend_class_entry *ce = Z_OBJCE_P(this_ptr);
     640                 : 
     641               0 :         ALLOC_ZVAL(method_args_ptr);
     642               0 :         INIT_PZVAL(method_args_ptr);
     643               0 :         array_init(method_args_ptr);
     644                 : 
     645               0 :         if (zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE) {
     646               0 :                 zval_dtor(method_args_ptr);
     647               0 :                 zend_error(E_ERROR, "Cannot get arguments for __call");
     648               0 :                 RETURN_FALSE;
     649                 :         }
     650                 : 
     651               0 :         ALLOC_ZVAL(method_name_ptr);
     652               0 :         INIT_PZVAL(method_name_ptr);
     653               0 :         ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */
     654                 : 
     655                 :         /* __call handler is called with two arguments:
     656                 :            method name
     657                 :            array of method parameters
     658                 : 
     659                 :         */
     660               0 :         zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
     661                 : 
     662               0 :         if (method_result_ptr) {
     663               0 :                 if (method_result_ptr->is_ref || method_result_ptr->refcount > 1) {
     664               0 :                         RETVAL_ZVAL(method_result_ptr, 1, 1);
     665                 :                 } else {
     666               0 :                         RETVAL_ZVAL(method_result_ptr, 0, 1);
     667                 :                 }
     668                 :         }
     669                 : 
     670                 :         /* now destruct all auxiliaries */
     671               0 :         zval_ptr_dtor(&method_args_ptr);
     672               0 :         zval_ptr_dtor(&method_name_ptr);
     673                 : 
     674                 :         /* destruct the function also, then - we have allocated it in get_method */
     675               0 :         efree(func);
     676                 : }
     677                 : 
     678                 : /* Ensures that we're allowed to call a private method.
     679                 :  * Returns the function address that should be called, or NULL
     680                 :  * if no such function exists.
     681                 :  */
     682                 : static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
     683               0 : {
     684               0 :         if (!ce) {
     685               0 :                 return 0;
     686                 :         }
     687                 : 
     688                 :         /* We may call a private function if:
     689                 :          * 1.  The class of our object is the same as the scope, and the private
     690                 :          *     function (EX(fbc)) has the same scope.
     691                 :          * 2.  One of our parent classes are the same as the scope, and it contains
     692                 :          *     a private function with the same name that has the same scope.
     693                 :          */
     694               0 :         if (fbc->common.scope == ce && EG(scope) == ce) {
     695                 :                 /* rule #1 checks out ok, allow the function call */
     696               0 :                 return fbc;
     697                 :         }
     698                 : 
     699                 : 
     700                 :         /* Check rule #2 */
     701               0 :         ce = ce->parent;
     702               0 :         while (ce) {
     703               0 :                 if (ce == EG(scope)) {
     704               0 :                         if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==SUCCESS
     705                 :                                 && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE
     706                 :                                 && fbc->common.scope == EG(scope)) {
     707               0 :                                 return fbc;
     708                 :                         }
     709               0 :                         break;
     710                 :                 }
     711               0 :                 ce = ce->parent;
     712                 :         }
     713               0 :         return NULL;
     714                 : }
     715                 : 
     716                 : 
     717                 : ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
     718               0 : {
     719               0 :         return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen TSRMLS_CC) != NULL;
     720                 : }
     721                 : 
     722                 : 
     723                 : /* Ensures that we're allowed to call a protected method.
     724                 :  */
     725                 : ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope)
     726             916 : {
     727             916 :         zend_class_entry *fbc_scope = ce;
     728                 : 
     729                 :         /* Is the context that's calling the function, the same as one of
     730                 :          * the function's parents?
     731                 :          */
     732            2588 :         while (fbc_scope) {
     733             916 :                 if (fbc_scope==scope) {
     734             160 :                         return 1;
     735                 :                 }
     736             756 :                 fbc_scope = fbc_scope->parent;
     737                 :         }
     738                 : 
     739                 :         /* Is the function's scope the same as our current object context,
     740                 :          * or any of the parents of our context?
     741                 :          */
     742            2274 :         while (scope) {
     743            1518 :                 if (scope==ce) {
     744             756 :                         return 1;
     745                 :                 }
     746             762 :                 scope = scope->parent;
     747                 :         }
     748               0 :         return 0;
     749                 : }
     750                 : 
     751                 : 
     752                 : static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc)
     753             748 : {
     754             748 :         return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
     755                 : }
     756                 : 
     757                 : 
     758                 : static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len TSRMLS_DC)
     759            1484 : {
     760                 :         zend_object *zobj;
     761                 :         zend_function *fbc;
     762                 :         char *lc_method_name;
     763            1484 :         zval *object = *object_ptr;
     764                 :         
     765            1484 :         lc_method_name = do_alloca(method_len+1);
     766                 :         /* Create a zend_copy_str_tolower(dest, src, src_length); */
     767            1484 :         zend_str_tolower_copy(lc_method_name, method_name, method_len);
     768                 :                 
     769            1484 :         zobj = Z_OBJ_P(object);
     770            1484 :         if (zend_hash_find(&zobj->ce->function_table, lc_method_name, method_len+1, (void **)&fbc) == FAILURE) {
     771                 :                 free_alloca(lc_method_name);
     772               0 :                 if (zobj->ce->__call) {
     773               0 :                         zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
     774               0 :                         call_user_call->type = ZEND_INTERNAL_FUNCTION;
     775               0 :                         call_user_call->module = zobj->ce->module;
     776               0 :                         call_user_call->handler = zend_std_call_user_call;
     777               0 :                         call_user_call->arg_info = NULL;
     778               0 :                         call_user_call->num_args = 0;
     779               0 :                         call_user_call->scope = zobj->ce;
     780               0 :                         call_user_call->fn_flags = 0;
     781               0 :                         call_user_call->function_name = estrndup(method_name, method_len);
     782               0 :                         call_user_call->pass_rest_by_reference = 0;
     783               0 :                         call_user_call->return_reference = ZEND_RETURN_VALUE;
     784                 : 
     785               0 :                         return (union _zend_function *)call_user_call;
     786                 :                 } else {
     787               0 :                         return NULL;
     788                 :                 }
     789                 :         }
     790                 : 
     791                 :         /* Check access level */
     792            1484 :         if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
     793                 :                 zend_function *updated_fbc;
     794                 : 
     795                 :                 /* Ensure that if we're calling a private function, we're allowed to do so.
     796                 :                  */
     797               0 :                 updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len TSRMLS_CC);
     798               0 :                 if (!updated_fbc) {
     799               0 :                         zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
     800                 :                 }
     801               0 :                 fbc = updated_fbc;
     802                 :         } else {
     803                 :                 /* Ensure that we haven't overridden a private function and end up calling
     804                 :                  * the overriding public function...
     805                 :                  */
     806            1484 :                 if (EG(scope) && fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
     807                 :                         zend_function *priv_fbc;
     808                 : 
     809               0 :                         if (zend_hash_find(&EG(scope)->function_table, lc_method_name, method_len+1, (void **) &priv_fbc)==SUCCESS
     810                 :                                 && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
     811                 :                                 && priv_fbc->common.scope == EG(scope)) {
     812               0 :                                 fbc = priv_fbc;
     813                 :                         }
     814                 :                 }
     815            1484 :                 if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
     816                 :                         /* Ensure that if we're calling a protected function, we're allowed to do so.
     817                 :                          */
     818             498 :                         if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
     819               0 :                                 zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), method_name, EG(scope) ? EG(scope)->name : "");
     820                 :                         }
     821                 :                 }
     822                 :         }
     823                 : 
     824                 :         free_alloca(lc_method_name);
     825            1484 :         return fbc;
     826                 : }
     827                 : 
     828                 : 
     829                 : /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
     830                 : ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC)
     831             294 : {
     832                 :         zend_function *fbc;
     833                 : 
     834             294 :         if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &fbc)==FAILURE) {
     835               0 :                 char *class_name = ce->name;
     836                 : 
     837               0 :                 if (!class_name) {
     838               0 :                         class_name = "";
     839                 :                 }
     840               0 :                 zend_error(E_ERROR, "Call to undefined method %s::%s()", class_name, function_name_strval);
     841                 :         }
     842             294 :         if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
     843                 :                 /* No further checks necessary, most common case */
     844             250 :         } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
     845                 :                 zend_function *updated_fbc;
     846                 : 
     847                 :                 /* Ensure that if we're calling a private function, we're allowed to do so.
     848                 :                  */
     849               0 :                 updated_fbc = zend_check_private_int(fbc, EG(scope), function_name_strval, function_name_strlen TSRMLS_CC);
     850               0 :                 if (!updated_fbc) {
     851               0 :                         zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
     852                 :                 }
     853               0 :                 fbc = updated_fbc;
     854             250 :         } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
     855                 :                 /* Ensure that if we're calling a protected function, we're allowed to do so.
     856                 :                  */
     857             250 :                 if (!zend_check_protected(zend_get_function_root_class(fbc), EG(scope))) {
     858               0 :                         zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), function_name_strval, EG(scope) ? EG(scope)->name : "");
     859                 :                 }
     860                 :         }
     861                 : 
     862             294 :         return fbc;
     863                 : }
     864                 : 
     865                 : 
     866                 : ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, char *property_name, int property_name_len, zend_bool silent TSRMLS_DC)
     867             105 : {
     868             105 :         zval **retval = NULL;
     869             105 :         zend_class_entry *tmp_ce = ce;
     870                 :         zend_property_info *property_info;
     871                 :         zend_property_info std_property_info;
     872                 : 
     873             105 :         if (zend_hash_find(&ce->properties_info, property_name, property_name_len+1, (void **) &property_info)==FAILURE || (property_info->flags & ZEND_ACC_SHADOW)) {
     874               0 :                 std_property_info.flags = ZEND_ACC_PUBLIC;
     875               0 :                 std_property_info.name = property_name;
     876               0 :                 std_property_info.name_length = property_name_len;
     877               0 :                 std_property_info.h = zend_get_hash_value(std_property_info.name, std_property_info.name_length+1);
     878               0 :                 std_property_info.ce = ce;
     879               0 :                 property_info = &std_property_info;
     880                 :         }
     881                 : 
     882                 : #if DEBUG_OBJECT_HANDLERS
     883                 :         zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags));
     884                 : #endif
     885                 : 
     886             105 :         if (!zend_verify_property_access(property_info, ce TSRMLS_CC)) {
     887               0 :                 if (!silent) {
     888               0 :                         zend_error(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
     889                 :                 }
     890               0 :                 return NULL;
     891                 :         }
     892                 : 
     893             105 :         zend_update_class_constants(tmp_ce TSRMLS_CC);
     894                 : 
     895             105 :         zend_hash_quick_find(CE_STATIC_MEMBERS(tmp_ce), property_info->name, property_info->name_length+1, property_info->h, (void **) &retval);
     896                 : 
     897             105 :         if (!retval) {
     898               0 :                 if (silent) {
     899               0 :                         return NULL;
     900                 :                 } else {
     901               0 :                         zend_error(E_ERROR, "Access to undeclared static property:  %s::$%s", ce->name, property_name);
     902                 :                 }
     903                 :         }
     904                 : 
     905             105 :         return retval;
     906                 : }
     907                 : 
     908                 : 
     909                 : ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, char *property_name, int property_name_len TSRMLS_DC)
     910               0 : {
     911               0 :         zend_error(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name);
     912               0 :         return 0;
     913                 : }
     914                 : 
     915                 : 
     916                 : ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC)
     917             118 : {
     918             118 :         zend_object *zobj = Z_OBJ_P(object);
     919             118 :         zend_function *constructor = zobj->ce->constructor;
     920                 : 
     921             118 :         if (constructor) {
     922             117 :                 if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) {
     923                 :                         /* No further checks necessary */
     924               0 :                 } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
     925                 :                         /* Ensure that if we're calling a private function, we're allowed to do so.
     926                 :                          */
     927               0 :                         if (Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC) != EG(scope)) {
     928               0 :                                 if (EG(scope)) {
     929               0 :                                         zend_error(E_ERROR, "Call to private %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
     930                 :                                 } else {
     931               0 :                                         zend_error(E_ERROR, "Call to private %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
     932                 :                                 }
     933                 :                         }
     934               0 :                 } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) {
     935                 :                         /* Ensure that if we're calling a protected function, we're allowed to do so.
     936                 :                          */
     937               0 :                         if (!zend_check_protected(zend_get_function_root_class(constructor), EG(scope))) {
     938               0 :                                 if (EG(scope)) {
     939               0 :                                         zend_error(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
     940                 :                                 } else {
     941               0 :                                         zend_error(E_ERROR, "Call to protected %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
     942                 :                                 }
     943                 :                         }
     944                 :                 }
     945                 :         }
     946                 : 
     947             118 :         return constructor;
     948                 : }
     949                 : 
     950                 : 
     951                 : int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC);
     952                 : 
     953                 : 
     954                 : static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC)
     955               0 : {
     956                 :         zend_object *zobj1, *zobj2;
     957                 : 
     958               0 :         zobj1 = Z_OBJ_P(o1);
     959               0 :         zobj2 = Z_OBJ_P(o2);
     960                 : 
     961               0 :         if (zobj1->ce != zobj2->ce) {
     962               0 :                 return 1; /* different classes */
     963                 :         }
     964               0 :         return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC);
     965                 : }
     966                 : 
     967                 : static int zend_std_has_property(zval *object, zval *member, int has_set_exists TSRMLS_DC)
     968               0 : {
     969                 :         zend_object *zobj;
     970                 :         int result;
     971                 :         zval **value;
     972               0 :         zval *tmp_member = NULL;
     973                 :         zend_property_info *property_info;
     974                 : 
     975               0 :         zobj = Z_OBJ_P(object);
     976                 : 
     977               0 :         if (member->type != IS_STRING) {
     978               0 :                 ALLOC_ZVAL(tmp_member);
     979               0 :                 *tmp_member = *member;
     980               0 :                 INIT_PZVAL(tmp_member);
     981               0 :                 zval_copy_ctor(tmp_member);
     982               0 :                 convert_to_string(tmp_member);
     983               0 :                 member = tmp_member;
     984                 :         }
     985                 : 
     986                 : #if DEBUG_OBJECT_HANDLERS
     987                 :         fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
     988                 : #endif
     989                 : 
     990               0 :         property_info = zend_get_property_info(zobj->ce, member, 1 TSRMLS_CC);
     991                 : 
     992               0 :         if (!property_info || zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE) {
     993                 :                 zend_guard *guard;
     994                 : 
     995               0 :                 result = 0;
     996               0 :                 if ((has_set_exists != 2) &&
     997                 :                     zobj->ce->__isset &&
     998                 :                     zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
     999                 :                     !guard->in_isset) {
    1000                 :                         zval *rv;
    1001                 : 
    1002                 :                         /* have issetter - try with it! */
    1003               0 :                         guard->in_isset = 1; /* prevent circular getting */
    1004               0 :                         rv = zend_std_call_issetter(object, member TSRMLS_CC);
    1005               0 :                         if (rv) {
    1006               0 :                                 result = zend_is_true(rv);
    1007               0 :                                 zval_ptr_dtor(&rv);
    1008               0 :                                 if (has_set_exists && result && !EG(exception) && zobj->ce->__get && !guard->in_get) {
    1009               0 :                                         guard->in_get = 1;
    1010               0 :                                         rv = zend_std_call_getter(object, member TSRMLS_CC);
    1011               0 :                                         guard->in_get = 0;
    1012               0 :                                         if (rv) {
    1013               0 :                                                 rv->refcount++;
    1014               0 :                                                 result = i_zend_is_true(rv);
    1015               0 :                                                 zval_ptr_dtor(&rv);
    1016                 :                                         }
    1017                 :                                 }
    1018                 :                         }
    1019               0 :                         guard->in_isset = 0;
    1020                 :                 }
    1021                 :         } else {
    1022               0 :                 switch (has_set_exists) {
    1023                 :                 case 0:
    1024               0 :                         result = (Z_TYPE_PP(value) != IS_NULL);
    1025               0 :                         break;
    1026                 :                 default:
    1027               0 :                         result = zend_is_true(*value);
    1028               0 :                         break;
    1029                 :                 case 2:
    1030               0 :                         result = 1;
    1031                 :                         break;
    1032                 :                 }
    1033                 :         }
    1034                 : 
    1035               0 :         if (tmp_member) {
    1036               0 :                 zval_ptr_dtor(&tmp_member);
    1037                 :         }
    1038               0 :         return result;
    1039                 : }
    1040                 : 
    1041                 : 
    1042                 : zend_class_entry *zend_std_object_get_class(zval *object TSRMLS_DC)
    1043             827 : {
    1044                 :         zend_object *zobj;
    1045             827 :         zobj = Z_OBJ_P(object);
    1046                 : 
    1047             827 :         return zobj->ce;
    1048                 : }
    1049                 : 
    1050                 : int zend_std_object_get_class_name(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
    1051              44 : {
    1052                 :         zend_object *zobj;
    1053                 :         zend_class_entry *ce;
    1054              44 :         zobj = Z_OBJ_P(object);
    1055                 : 
    1056              44 :         if (parent) {
    1057               0 :                 if (!zobj->ce->parent) {
    1058               0 :                         return FAILURE;
    1059                 :                 }
    1060               0 :                 ce = zobj->ce->parent;
    1061                 :         } else {
    1062              44 :                 ce = zobj->ce;
    1063                 :         }
    1064                 : 
    1065              44 :         *class_name_len = ce->name_length;
    1066              44 :         *class_name = estrndup(ce->name, ce->name_length);
    1067              44 :         return SUCCESS;
    1068                 : }
    1069                 : 
    1070                 : ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC)
    1071              16 : {
    1072                 :         zval *retval;
    1073                 :         zend_class_entry *ce;
    1074                 : 
    1075              16 :         switch (type) {
    1076                 :                 case IS_STRING:
    1077               6 :                         ce = Z_OBJCE_P(readobj);
    1078               6 :                         if (ce->__tostring &&
    1079                 :                 (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
    1080               6 :                 if (EG(exception)) {
    1081               0 :                         if (retval) {
    1082               0 :                                 zval_ptr_dtor(&retval);
    1083                 :                         }
    1084               0 :                                         zend_error(E_ERROR, "Method %s::__toString() must not throw an exception", ce->name);
    1085               0 :                         return FAILURE;
    1086                 :                 }
    1087               6 :                                 if (Z_TYPE_P(retval) == IS_STRING) {
    1088               6 :                                         INIT_PZVAL(writeobj);
    1089               6 :                                         ZVAL_ZVAL(writeobj, retval, 1, 1);
    1090               6 :                                         if (Z_TYPE_P(writeobj) != type) {
    1091               0 :                                                 convert_to_explicit_type(writeobj, type);
    1092                 :                                         }
    1093               6 :                                         return SUCCESS;
    1094                 :                                 } else {
    1095               0 :                                         zval_ptr_dtor(&retval);
    1096               0 :                                         INIT_PZVAL(writeobj);
    1097               0 :                                         ZVAL_EMPTY_STRING(writeobj);
    1098               0 :                                         zend_error(E_RECOVERABLE_ERROR, "Method %s::__toString() must return a string value", ce->name);
    1099               0 :                                         return SUCCESS;
    1100                 :                                 }
    1101                 :                         }
    1102               0 :                         return FAILURE;
    1103                 :                 case IS_BOOL:
    1104              10 :                         INIT_PZVAL(writeobj);
    1105              10 :                         ZVAL_BOOL(writeobj, 1);
    1106              10 :                         return SUCCESS;
    1107                 :                 case IS_LONG:
    1108               0 :                         ce = Z_OBJCE_P(readobj);
    1109               0 :                         zend_error(E_NOTICE, "Object of class %s could not be converted to int", ce->name);
    1110               0 :                         INIT_PZVAL(writeobj);
    1111               0 :                         ZVAL_LONG(writeobj, 1);
    1112               0 :                         return SUCCESS;
    1113                 :                 case IS_DOUBLE:
    1114               0 :                         ce = Z_OBJCE_P(readobj);
    1115               0 :                         zend_error(E_NOTICE, "Object of class %s could not be converted to double", ce->name);
    1116               0 :                         INIT_PZVAL(writeobj);
    1117               0 :                         ZVAL_DOUBLE(writeobj, 1);
    1118               0 :                         return SUCCESS;
    1119                 :                 default:
    1120                 :                         break;
    1121                 :         }
    1122               0 :         return FAILURE;
    1123                 : }
    1124                 : 
    1125                 : 
    1126                 : ZEND_API zend_object_handlers std_object_handlers = {
    1127                 :         zend_objects_store_add_ref,                             /* add_ref */
    1128                 :         zend_objects_store_del_ref,                             /* del_ref */
    1129                 :         zend_objects_clone_obj,                                 /* clone_obj */
    1130                 : 
    1131                 :         zend_std_read_property,                                 /* read_property */
    1132                 :         zend_std_write_property,                                /* write_property */
    1133                 :         zend_std_read_dimension,                                /* read_dimension */
    1134                 :         zend_std_write_dimension,                               /* write_dimension */
    1135                 :         zend_std_get_property_ptr_ptr,                  /* get_property_ptr_ptr */
    1136                 :         NULL,                                                                   /* get */
    1137                 :         NULL,                                                                   /* set */
    1138                 :         zend_std_has_property,                                  /* has_property */
    1139                 :         zend_std_unset_property,                                /* unset_property */
    1140                 :         zend_std_has_dimension,                                 /* has_dimension */
    1141                 :         zend_std_unset_dimension,                               /* unset_dimension */
    1142                 :         zend_std_get_properties,                                /* get_properties */
    1143                 :         zend_std_get_method,                                    /* get_method */
    1144                 :         NULL,                                                                   /* call_method */
    1145                 :         zend_std_get_constructor,                               /* get_constructor */
    1146                 :         zend_std_object_get_class,                              /* get_class_entry */
    1147                 :         zend_std_object_get_class_name,                 /* get_class_name */
    1148                 :         zend_std_compare_objects,                               /* compare_objects */
    1149                 :         zend_std_cast_object_tostring,                  /* cast_object */
    1150                 :         NULL,                                                                   /* count_elements */
    1151                 : };
    1152                 : 
    1153                 : /*
    1154                 :  * Local variables:
    1155                 :  * tab-width: 4
    1156                 :  * c-basic-offset: 4
    1157                 :  * indent-tabs-mode: t
    1158                 :  * End:
    1159                 :  */

Generated by: LTP GCOV extension version 1.5