Annotation of embedaddon/php/Zend/zend_object_handlers.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | Zend Engine                                                          |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1998-2012 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: 
1.1.1.2 ! misho      20: /* $Id$ */
1.1       misho      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: #include "zend_closures.h"
                     31: #include "zend_compile.h"
                     32: 
                     33: #define DEBUG_OBJECT_HANDLERS 0
                     34: 
1.1.1.2 ! misho      35: #define Z_OBJ_P(zval_p) \
        !            36:        ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].bucket.obj.object))
1.1       misho      37: 
                     38: /*
                     39:   __X accessors explanation:
                     40: 
                     41:   if we have __get and property that is not part of the properties array is
                     42:   requested, we call __get handler. If it fails, we return uninitialized.
                     43: 
                     44:   if we have __set and property that is not part of the properties array is
                     45:   set, we call __set handler. If it fails, we do not change the array.
                     46: 
                     47:   for both handlers above, when we are inside __get/__set, no further calls for
                     48:   __get/__set for this property of this object will be made, to prevent endless
                     49:   recursion and enable accessors to change properties array.
                     50: 
                     51:   if we have __call and method which is not part of the class function table is
                     52:   called, we cal __call handler.
                     53: */
                     54: 
1.1.1.2 ! misho      55: ZEND_API void rebuild_object_properties(zend_object *zobj) /* {{{ */
        !            56: {
        !            57:        if (!zobj->properties) {
        !            58:                HashPosition pos;
        !            59:                zend_property_info *prop_info;
        !            60:                zend_class_entry *ce = zobj->ce;
        !            61: 
        !            62:                ALLOC_HASHTABLE(zobj->properties);
        !            63:                zend_hash_init(zobj->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
        !            64:                if (ce->default_properties_count) {
        !            65:                        for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
        !            66:                             zend_hash_get_current_data_ex(&ce->properties_info, (void**)&prop_info, &pos) == SUCCESS;
        !            67:                             zend_hash_move_forward_ex(&ce->properties_info, &pos)) {
        !            68:                                if (/*prop_info->ce == ce &&*/
        !            69:                                    (prop_info->flags & ZEND_ACC_STATIC) == 0 && 
        !            70:                                    prop_info->offset >= 0 &&
        !            71:                                    zobj->properties_table[prop_info->offset]) {
        !            72:                                        zend_hash_quick_add(zobj->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&zobj->properties_table[prop_info->offset], sizeof(zval*), (void**)&zobj->properties_table[prop_info->offset]);
        !            73:                                }                               
        !            74:                        }
        !            75:                        while (ce->parent && ce->parent->default_properties_count) {
        !            76:                                ce = ce->parent;
        !            77:                                for (zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos);
        !            78:                                     zend_hash_get_current_data_ex(&ce->properties_info, (void**)&prop_info, &pos) == SUCCESS;
        !            79:                                     zend_hash_move_forward_ex(&ce->properties_info, &pos)) {
        !            80:                                        if (prop_info->ce == ce &&
        !            81:                                            (prop_info->flags & ZEND_ACC_STATIC) == 0 && 
        !            82:                                            (prop_info->flags & ZEND_ACC_PRIVATE) != 0 && 
        !            83:                                            prop_info->offset >= 0 &&
        !            84:                                                zobj->properties_table[prop_info->offset]) {
        !            85:                                                zend_hash_quick_add(zobj->properties, prop_info->name, prop_info->name_length+1, prop_info->h, (void**)&zobj->properties_table[prop_info->offset], sizeof(zval*), (void**)&zobj->properties_table[prop_info->offset]);
        !            86:                                        }                               
        !            87:                                }
        !            88:                        }
        !            89:                }
        !            90:        }
        !            91: }
        !            92: /* }}} */
        !            93: 
1.1       misho      94: ZEND_API HashTable *zend_std_get_properties(zval *object TSRMLS_DC) /* {{{ */
                     95: {
                     96:        zend_object *zobj;
                     97:        zobj = Z_OBJ_P(object);
1.1.1.2 ! misho      98:        if (!zobj->properties) {
        !            99:                rebuild_object_properties(zobj);
        !           100:        }
1.1       misho     101:        return zobj->properties;
                    102: }
                    103: /* }}} */
                    104: 
1.1.1.2 ! misho     105: ZEND_API HashTable *zend_std_get_gc(zval *object, zval ***table, int *n TSRMLS_DC) /* {{{ */
        !           106: {
        !           107:        if (Z_OBJ_HANDLER_P(object, get_properties) != zend_std_get_properties) {
        !           108:                *table = NULL;
        !           109:                *n = 0;
        !           110:                return Z_OBJ_HANDLER_P(object, get_properties)(object TSRMLS_CC);
        !           111:        } else {
        !           112:                zend_object *zobj = Z_OBJ_P(object);
        !           113: 
        !           114:                if (zobj->properties) {
        !           115:                        *table = NULL;
        !           116:                        *n = 0;
        !           117:                        return zobj->properties;
        !           118:                } else {
        !           119:                        *table = zobj->properties_table;
        !           120:                        *n = zobj->ce->default_properties_count;
        !           121:                        return NULL;
        !           122:                }
        !           123:        }
        !           124: }
        !           125: /* }}} */
        !           126: 
1.1       misho     127: ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
                    128: {
                    129:        *is_temp = 0;
                    130:        return zend_std_get_properties(object TSRMLS_CC);
                    131: }
                    132: /* }}} */
                    133: 
                    134: static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    135: {
                    136:        zval *retval = NULL;
                    137:        zend_class_entry *ce = Z_OBJCE_P(object);
                    138: 
                    139:        /* __get handler is called with one argument:
                    140:              property name
                    141: 
                    142:           it should return whether the call was successfull or not
                    143:        */
                    144: 
                    145:        SEPARATE_ARG_IF_REF(member);
                    146: 
                    147:        zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member);
                    148: 
                    149:        zval_ptr_dtor(&member);
                    150: 
                    151:        if (retval) {
                    152:                Z_DELREF_P(retval);
                    153:        }
                    154: 
                    155:        return retval;
                    156: }
                    157: /* }}} */
                    158: 
                    159: static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */
                    160: {
                    161:        zval *retval = NULL;
                    162:        int result;
                    163:        zend_class_entry *ce = Z_OBJCE_P(object);
                    164: 
                    165:        SEPARATE_ARG_IF_REF(member);
                    166:        Z_ADDREF_P(value);
                    167: 
                    168:        /* __set handler is called with two arguments:
                    169:             property name
                    170:             value to be set
                    171: 
                    172:           it should return whether the call was successfull or not
                    173:        */
                    174:        zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value);
                    175: 
                    176:        zval_ptr_dtor(&member);
                    177:        zval_ptr_dtor(&value);
                    178: 
                    179:        if (retval) {
                    180:                result = i_zend_is_true(retval) ? SUCCESS : FAILURE;
                    181:                zval_ptr_dtor(&retval);
                    182:                return result;
                    183:        } else {
                    184:                return FAILURE;
                    185:        }
                    186: }
                    187: /* }}} */
                    188: 
                    189: static void zend_std_call_unsetter(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    190: {
                    191:        zend_class_entry *ce = Z_OBJCE_P(object);
                    192: 
                    193:        /* __unset handler is called with one argument:
                    194:              property name
                    195:        */
                    196: 
                    197:        SEPARATE_ARG_IF_REF(member);
                    198: 
                    199:        zend_call_method_with_1_params(&object, ce, &ce->__unset, ZEND_UNSET_FUNC_NAME, NULL, member);
                    200: 
                    201:        zval_ptr_dtor(&member);
                    202: }
                    203: /* }}} */
                    204: 
                    205: static zval *zend_std_call_issetter(zval *object, zval *member TSRMLS_DC) /* {{{ */
                    206: {
                    207:        zval *retval = NULL;
                    208:        zend_class_entry *ce = Z_OBJCE_P(object);
                    209: 
                    210:        /* __isset handler is called with one argument:
                    211:              property name
                    212: 
                    213:           it should return whether the property is set or not
                    214:        */
                    215: 
                    216:        SEPARATE_ARG_IF_REF(member);
                    217: 
                    218:        zend_call_method_with_1_params(&object, ce, &ce->__isset, ZEND_ISSET_FUNC_NAME, &retval, member);
                    219: 
                    220:        zval_ptr_dtor(&member);
                    221: 
                    222:        return retval;
                    223: }
                    224: /* }}} */
                    225: 
1.1.1.2 ! misho     226: static zend_always_inline int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC) /* {{{ */
1.1       misho     227: {
                    228:        switch (property_info->flags & ZEND_ACC_PPP_MASK) {
                    229:                case ZEND_ACC_PUBLIC:
                    230:                        return 1;
                    231:                case ZEND_ACC_PROTECTED:
                    232:                        return zend_check_protected(property_info->ce, EG(scope));
                    233:                case ZEND_ACC_PRIVATE:
                    234:                        if ((ce==EG(scope) || property_info->ce == EG(scope)) && EG(scope)) {
                    235:                                return 1;
                    236:                        } else {
                    237:                                return 0;
                    238:                        }
                    239:                        break;
                    240:        }
                    241:        return 0;
                    242: }
                    243: /* }}} */
                    244: 
1.1.1.2 ! misho     245: static zend_always_inline zend_bool is_derived_class(zend_class_entry *child_class, zend_class_entry *parent_class) /* {{{ */
1.1       misho     246: {
                    247:        child_class = child_class->parent;
                    248:        while (child_class) {
                    249:                if (child_class == parent_class) {
                    250:                        return 1;
                    251:                }
                    252:                child_class = child_class->parent;
                    253:        }
                    254: 
                    255:        return 0;
                    256: }
                    257: /* }}} */
                    258: 
1.1.1.2 ! misho     259: static zend_always_inline struct _zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zval *member, int silent, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho     260: {
1.1.1.2 ! misho     261:        zend_property_info *property_info;
1.1       misho     262:        zend_property_info *scope_property_info;
                    263:        zend_bool denied_access = 0;
                    264:        ulong h;
                    265: 
1.1.1.2 ! misho     266:        if (key && (property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) != NULL) {
        !           267:                return property_info;
        !           268:        }
        !           269: 
        !           270:        if (UNEXPECTED(Z_STRVAL_P(member)[0] == '\0')) {
1.1       misho     271:                if (!silent) {
                    272:                        if (Z_STRLEN_P(member) == 0) {
1.1.1.2 ! misho     273:                                zend_error_noreturn(E_ERROR, "Cannot access empty property");
1.1       misho     274:                        } else {
1.1.1.2 ! misho     275:                                zend_error_noreturn(E_ERROR, "Cannot access property started with '\\0'");
1.1       misho     276:                        }
                    277:                }
                    278:                return NULL;
                    279:        }
1.1.1.2 ! misho     280:        property_info = NULL;
        !           281:        h = key ? key->hash_value : zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
1.1       misho     282:        if (zend_hash_quick_find(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &property_info)==SUCCESS) {
1.1.1.2 ! misho     283:                if (UNEXPECTED((property_info->flags & ZEND_ACC_SHADOW) != 0)) {
1.1       misho     284:                        /* if it's a shadow - go to access it's private */
                    285:                        property_info = NULL;
                    286:                } else {
1.1.1.2 ! misho     287:                        if (EXPECTED(zend_verify_property_access(property_info, ce TSRMLS_CC) != 0)) {
        !           288:                                if (EXPECTED((property_info->flags & ZEND_ACC_CHANGED) != 0)
        !           289:                                        && EXPECTED(!(property_info->flags & ZEND_ACC_PRIVATE))) {
1.1       misho     290:                                        /* We still need to make sure that we're not in a context
                    291:                                         * where the right property is a different 'statically linked' private
                    292:                                         * continue checking below...
                    293:                                         */
                    294:                                } else {
1.1.1.2 ! misho     295:                                        if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0) && !silent) {
1.1       misho     296:                                                zend_error(E_STRICT, "Accessing static property %s::$%s as non static", ce->name, Z_STRVAL_P(member));
                    297:                                        }
1.1.1.2 ! misho     298:                                        if (key) {
        !           299:                                                CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info);
        !           300:                                        }
1.1       misho     301:                                        return property_info;
                    302:                                }
                    303:                        } else {
                    304:                                /* Try to look in the scope instead */
                    305:                                denied_access = 1;
                    306:                        }
                    307:                }
                    308:        }
                    309:        if (EG(scope) != ce
                    310:                && EG(scope)
1.1.1.2 ! misho     311:                && is_derived_class(ce, EG(scope))
1.1       misho     312:                && zend_hash_quick_find(&EG(scope)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, h, (void **) &scope_property_info)==SUCCESS
                    313:                && scope_property_info->flags & ZEND_ACC_PRIVATE) {
1.1.1.2 ! misho     314:                if (key) {
        !           315:                        CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, scope_property_info);
        !           316:                }
1.1       misho     317:                return scope_property_info;
                    318:        } else if (property_info) {
1.1.1.2 ! misho     319:                if (UNEXPECTED(denied_access != 0)) {
1.1       misho     320:                        /* Information was available, but we were denied access.  Error out. */
1.1.1.2 ! misho     321:                        if (!silent) {
        !           322:                                zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, Z_STRVAL_P(member));
1.1       misho     323:                        }
1.1.1.2 ! misho     324:                        return NULL;
1.1       misho     325:                } else {
                    326:                        /* fall through, return property_info... */
1.1.1.2 ! misho     327:                        if (key) {
        !           328:                                CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info);
        !           329:                        }
1.1       misho     330:                }
                    331:        } else {
                    332:                EG(std_property_info).flags = ZEND_ACC_PUBLIC;
                    333:                EG(std_property_info).name = Z_STRVAL_P(member);
                    334:                EG(std_property_info).name_length = Z_STRLEN_P(member);
                    335:                EG(std_property_info).h = h;
                    336:                EG(std_property_info).ce = ce;
1.1.1.2 ! misho     337:                EG(std_property_info).offset = -1;
1.1       misho     338:                property_info = &EG(std_property_info);
                    339:        }
                    340:        return property_info;
                    341: }
                    342: /* }}} */
                    343: 
1.1.1.2 ! misho     344: ZEND_API struct _zend_property_info *zend_get_property_info(zend_class_entry *ce, zval *member, int silent TSRMLS_DC) /* {{{ */
        !           345: {
        !           346:        return zend_get_property_info_quick(ce, member, silent, NULL TSRMLS_CC);
        !           347: }
        !           348: /* }}} */
        !           349: 
        !           350: ZEND_API int zend_check_property_access(zend_object *zobj, const char *prop_info_name, int prop_info_name_len TSRMLS_DC) /* {{{ */
1.1       misho     351: {
                    352:        zend_property_info *property_info;
1.1.1.2 ! misho     353:        const char *class_name, *prop_name;
1.1       misho     354:        zval member;
                    355: 
                    356:        zend_unmangle_property_name(prop_info_name, prop_info_name_len, &class_name, &prop_name);
                    357:        ZVAL_STRING(&member, prop_name, 0);
1.1.1.2 ! misho     358:        property_info = zend_get_property_info_quick(zobj->ce, &member, 1, NULL TSRMLS_CC);
1.1       misho     359:        if (!property_info) {
                    360:                return FAILURE;
                    361:        }
                    362:        if (class_name && class_name[0] != '*') {
                    363:                if (!(property_info->flags & ZEND_ACC_PRIVATE)) {
                    364:                        /* we we're looking for a private prop but found a non private one of the same name */
                    365:                        return FAILURE;
                    366:                } else if (strcmp(prop_info_name+1, property_info->name+1)) {
                    367:                        /* we we're looking for a private prop but found a private one of the same name but another class */
                    368:                        return FAILURE;
                    369:                }
                    370:        }
                    371:        return zend_verify_property_access(property_info, zobj->ce TSRMLS_CC) ? SUCCESS : FAILURE;
                    372: }
                    373: /* }}} */
                    374: 
                    375: static int zend_get_property_guard(zend_object *zobj, zend_property_info *property_info, zval *member, zend_guard **pguard) /* {{{ */
                    376: {
                    377:        zend_property_info info;
                    378:        zend_guard stub;
                    379: 
                    380:        if (!property_info) {
                    381:                property_info = &info;
                    382:                info.name = Z_STRVAL_P(member);
                    383:                info.name_length = Z_STRLEN_P(member);
                    384:                info.h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
                    385:        }
                    386:        if (!zobj->guards) {
                    387:                ALLOC_HASHTABLE(zobj->guards);
                    388:                zend_hash_init(zobj->guards, 0, NULL, NULL, 0);
                    389:        } else if (zend_hash_quick_find(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void **) pguard) == SUCCESS) {
                    390:                return SUCCESS;
                    391:        }
                    392:        stub.in_get = 0;
                    393:        stub.in_set = 0;
                    394:        stub.in_unset = 0;
                    395:        stub.in_isset = 0;
                    396:        return zend_hash_quick_add(zobj->guards, property_info->name, property_info->name_length+1, property_info->h, (void**)&stub, sizeof(stub), (void**) pguard);
                    397: }
                    398: /* }}} */
                    399: 
1.1.1.2 ! misho     400: zval *zend_std_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho     401: {
                    402:        zend_object *zobj;
                    403:        zval *tmp_member = NULL;
                    404:        zval **retval;
                    405:        zval *rv = NULL;
                    406:        zend_property_info *property_info;
                    407:        int silent;
                    408: 
                    409:        silent = (type == BP_VAR_IS);
                    410:        zobj = Z_OBJ_P(object);
                    411: 
1.1.1.2 ! misho     412:        if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
        !           413:                ALLOC_ZVAL(tmp_member);
1.1       misho     414:                *tmp_member = *member;
                    415:                INIT_PZVAL(tmp_member);
                    416:                zval_copy_ctor(tmp_member);
                    417:                convert_to_string(tmp_member);
                    418:                member = tmp_member;
1.1.1.2 ! misho     419:                key = NULL;
1.1       misho     420:        }
                    421: 
                    422: #if DEBUG_OBJECT_HANDLERS
                    423:        fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
                    424: #endif
                    425: 
                    426:        /* make zend_get_property_info silent if we have getter - we may want to use it */
1.1.1.2 ! misho     427:        property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC);
1.1       misho     428: 
1.1.1.2 ! misho     429:        if (UNEXPECTED(!property_info) ||
        !           430:            ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
        !           431:             property_info->offset >= 0) ?
        !           432:                (zobj->properties ?
        !           433:                    ((retval = (zval**)zobj->properties_table[property_info->offset]) == NULL) :
        !           434:                    (*(retval = &zobj->properties_table[property_info->offset]) == NULL)) :
        !           435:                (UNEXPECTED(!zobj->properties) ||
        !           436:                  UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)))) {
1.1       misho     437:                zend_guard *guard = NULL;
                    438: 
                    439:                if (zobj->ce->__get &&
                    440:                    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
                    441:                    !guard->in_get) {
                    442:                        /* have getter - try with it! */
                    443:                        Z_ADDREF_P(object);
                    444:                        if (PZVAL_IS_REF(object)) {
                    445:                                SEPARATE_ZVAL(&object);
                    446:                        }
                    447:                        guard->in_get = 1; /* prevent circular getting */
                    448:                        rv = zend_std_call_getter(object, member TSRMLS_CC);
                    449:                        guard->in_get = 0;
                    450: 
                    451:                        if (rv) {
                    452:                                retval = &rv;
                    453:                                if (!Z_ISREF_P(rv) &&
                    454:                                    (type == BP_VAR_W || type == BP_VAR_RW  || type == BP_VAR_UNSET)) {
                    455:                                        if (Z_REFCOUNT_P(rv) > 0) {
                    456:                                                zval *tmp = rv;
                    457: 
                    458:                                                ALLOC_ZVAL(rv);
                    459:                                                *rv = *tmp;
                    460:                                                zval_copy_ctor(rv);
                    461:                                                Z_UNSET_ISREF_P(rv);
                    462:                                                Z_SET_REFCOUNT_P(rv, 0);
                    463:                                        }
1.1.1.2 ! misho     464:                                        if (UNEXPECTED(Z_TYPE_P(rv) != IS_OBJECT)) {
1.1       misho     465:                                                zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", zobj->ce->name, Z_STRVAL_P(member));
                    466:                                        }
                    467:                                }
                    468:                        } else {
                    469:                                retval = &EG(uninitialized_zval_ptr);
                    470:                        }
                    471:                        if (EXPECTED(*retval != object)) {
                    472:                                zval_ptr_dtor(&object);
                    473:                        } else {
                    474:                                Z_DELREF_P(object);
                    475:                        }
                    476:                } else {
                    477:                        if (zobj->ce->__get && guard && guard->in_get == 1) {
                    478:                                if (Z_STRVAL_P(member)[0] == '\0') {
                    479:                                        if (Z_STRLEN_P(member) == 0) {
                    480:                                                zend_error(E_ERROR, "Cannot access empty property");
                    481:                                        } else {
                    482:                                                zend_error(E_ERROR, "Cannot access property started with '\\0'");
                    483:                                        }
                    484:                                }
                    485:                        }
                    486:                        if (!silent) {
                    487:                                zend_error(E_NOTICE,"Undefined property: %s::$%s", zobj->ce->name, Z_STRVAL_P(member));
                    488:                        }
                    489:                        retval = &EG(uninitialized_zval_ptr);
                    490:                }
                    491:        }
1.1.1.2 ! misho     492:        if (UNEXPECTED(tmp_member != NULL)) {
1.1       misho     493:                Z_ADDREF_PP(retval);
                    494:                zval_ptr_dtor(&tmp_member);
                    495:                Z_DELREF_PP(retval);
                    496:        }
                    497:        return *retval;
                    498: }
                    499: /* }}} */
                    500: 
1.1.1.2 ! misho     501: ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho     502: {
                    503:        zend_object *zobj;
                    504:        zval *tmp_member = NULL;
                    505:        zval **variable_ptr;
                    506:        zend_property_info *property_info;
                    507: 
                    508:        zobj = Z_OBJ_P(object);
                    509: 
1.1.1.2 ! misho     510:        if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
1.1       misho     511:                ALLOC_ZVAL(tmp_member);
                    512:                *tmp_member = *member;
                    513:                INIT_PZVAL(tmp_member);
                    514:                zval_copy_ctor(tmp_member);
                    515:                convert_to_string(tmp_member);
                    516:                member = tmp_member;
1.1.1.2 ! misho     517:                key = NULL;
1.1       misho     518:        }
                    519: 
1.1.1.2 ! misho     520:        property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__set != NULL), key TSRMLS_CC);
1.1       misho     521: 
1.1.1.2 ! misho     522:        if (EXPECTED(property_info != NULL) &&
        !           523:            ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
        !           524:             property_info->offset >= 0) ?
        !           525:                (zobj->properties ?
        !           526:                    ((variable_ptr = (zval**)zobj->properties_table[property_info->offset]) != NULL) :
        !           527:                    (*(variable_ptr = &zobj->properties_table[property_info->offset]) != NULL)) :
        !           528:                (EXPECTED(zobj->properties != NULL) &&
        !           529:                  EXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS)))) {
1.1       misho     530:                /* if we already have this value there, we don't actually need to do anything */
1.1.1.2 ! misho     531:                if (EXPECTED(*variable_ptr != value)) {
1.1       misho     532:                        /* if we are assigning reference, we shouldn't move it, but instead assign variable
                    533:                           to the same pointer */
                    534:                        if (PZVAL_IS_REF(*variable_ptr)) {
                    535:                                zval garbage = **variable_ptr; /* old value should be destroyed */
                    536: 
                    537:                                /* To check: can't *variable_ptr be some system variable like error_zval here? */
                    538:                                Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value);
                    539:                                (*variable_ptr)->value = value->value;
                    540:                                if (Z_REFCOUNT_P(value) > 0) {
                    541:                                        zval_copy_ctor(*variable_ptr);
                    542:                                }
                    543:                                zval_dtor(&garbage);
                    544:                        } else {
                    545:                                zval *garbage = *variable_ptr;
                    546: 
                    547:                                /* if we assign referenced variable, we should separate it */
                    548:                                Z_ADDREF_P(value);
                    549:                                if (PZVAL_IS_REF(value)) {
                    550:                                        SEPARATE_ZVAL(&value);
                    551:                                }
                    552:                                *variable_ptr = value;
                    553:                                zval_ptr_dtor(&garbage);
                    554:                        }
                    555:                }
                    556:        } else {
                    557:                zend_guard *guard = NULL;
                    558: 
                    559:                if (zobj->ce->__set &&
                    560:                    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
                    561:                    !guard->in_set) {
                    562:                        Z_ADDREF_P(object);
                    563:                        if (PZVAL_IS_REF(object)) {
                    564:                                SEPARATE_ZVAL(&object);
                    565:                        }
                    566:                        guard->in_set = 1; /* prevent circular setting */
                    567:                        if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) {
                    568:                                /* for now, just ignore it - __set should take care of warnings, etc. */
                    569:                        }
                    570:                        guard->in_set = 0;
                    571:                        zval_ptr_dtor(&object);
1.1.1.2 ! misho     572:                } else if (EXPECTED(property_info != NULL)) {
1.1       misho     573:                        /* if we assign referenced variable, we should separate it */
                    574:                        Z_ADDREF_P(value);
                    575:                        if (PZVAL_IS_REF(value)) {
                    576:                                SEPARATE_ZVAL(&value);
                    577:                        }
1.1.1.2 ! misho     578:                        if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
        !           579:                            property_info->offset >= 0) {
        !           580:                                        if (!zobj->properties) {
        !           581:                                                zobj->properties_table[property_info->offset] = value;
        !           582:                                        } else if (zobj->properties_table[property_info->offset]) {
        !           583:                                                *(zval**)zobj->properties_table[property_info->offset] = value;
        !           584:                                        } else {
        !           585:                                                zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]);
        !           586:                                        }
        !           587:                                } else {
        !           588:                                        if (!zobj->properties) {
        !           589:                                        rebuild_object_properties(zobj);
        !           590:                                }
        !           591:                                zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), NULL);
        !           592:                        }
1.1       misho     593:                } else if (zobj->ce->__set && guard && guard->in_set == 1) {
                    594:                        if (Z_STRVAL_P(member)[0] == '\0') {
                    595:                                if (Z_STRLEN_P(member) == 0) {
                    596:                                        zend_error(E_ERROR, "Cannot access empty property");
                    597:                                } else {
                    598:                                        zend_error(E_ERROR, "Cannot access property started with '\\0'");
                    599:                                }
                    600:                        }
                    601:                }
                    602:        }
                    603: 
1.1.1.2 ! misho     604:        if (UNEXPECTED(tmp_member != NULL)) {
1.1       misho     605:                zval_ptr_dtor(&tmp_member);
                    606:        }
                    607: }
                    608: /* }}} */
                    609: 
                    610: zval *zend_std_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
                    611: {
                    612:        zend_class_entry *ce = Z_OBJCE_P(object);
                    613:        zval *retval;
                    614: 
1.1.1.2 ! misho     615:        if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC) != 0)) {
1.1       misho     616:                if(offset == NULL) {
                    617:                        /* [] construct */
                    618:                        ALLOC_INIT_ZVAL(offset);
                    619:                } else {
                    620:                        SEPARATE_ARG_IF_REF(offset);
                    621:                }
                    622:                zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
                    623: 
                    624:                zval_ptr_dtor(&offset);
                    625: 
1.1.1.2 ! misho     626:                if (UNEXPECTED(!retval)) {
        !           627:                        if (UNEXPECTED(!EG(exception))) {
        !           628:                                zend_error_noreturn(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
1.1       misho     629:                        }
                    630:                        return 0;
                    631:                }
                    632: 
                    633:                /* Undo PZVAL_LOCK() */
                    634:                Z_DELREF_P(retval);
                    635: 
                    636:                return retval;
                    637:        } else {
1.1.1.2 ! misho     638:                zend_error_noreturn(E_ERROR, "Cannot use object of type %s as array", ce->name);
1.1       misho     639:                return 0;
                    640:        }
                    641: }
                    642: /* }}} */
                    643: 
                    644: static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
                    645: {
                    646:        zend_class_entry *ce = Z_OBJCE_P(object);
                    647: 
1.1.1.2 ! misho     648:        if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC) != 0)) {
1.1       misho     649:                if (!offset) {
                    650:                        ALLOC_INIT_ZVAL(offset);
                    651:                } else {
                    652:                        SEPARATE_ARG_IF_REF(offset);
                    653:                }
                    654:                zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value);
                    655:                zval_ptr_dtor(&offset);
                    656:        } else {
1.1.1.2 ! misho     657:                zend_error_noreturn(E_ERROR, "Cannot use object of type %s as array", ce->name);
1.1       misho     658:        }
                    659: }
                    660: /* }}} */
                    661: 
                    662: static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
                    663: {
                    664:        zend_class_entry *ce = Z_OBJCE_P(object);
                    665:        zval *retval;
                    666:        int result;
                    667: 
1.1.1.2 ! misho     668:        if (EXPECTED(instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC) != 0)) {
1.1       misho     669:                SEPARATE_ARG_IF_REF(offset);
                    670:                zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
1.1.1.2 ! misho     671:                if (EXPECTED(retval != NULL)) {
1.1       misho     672:                        result = i_zend_is_true(retval);
                    673:                        zval_ptr_dtor(&retval);
1.1.1.2 ! misho     674:                        if (check_empty && result && EXPECTED(!EG(exception))) {
1.1       misho     675:                                zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
                    676:                                if (retval) {
                    677:                                        result = i_zend_is_true(retval);
                    678:                                        zval_ptr_dtor(&retval);
                    679:                                }
                    680:                        }
                    681:                } else {
                    682:                        result = 0;
                    683:                }
                    684:                zval_ptr_dtor(&offset);
                    685:        } else {
1.1.1.2 ! misho     686:                zend_error_noreturn(E_ERROR, "Cannot use object of type %s as array", ce->name);
1.1       misho     687:                return 0;
                    688:        }
                    689:        return result;
                    690: }
                    691: /* }}} */
                    692: 
1.1.1.2 ! misho     693: static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho     694: {
                    695:        zend_object *zobj;
                    696:        zval tmp_member;
                    697:        zval **retval;
                    698:        zend_property_info *property_info;
                    699: 
                    700:        zobj = Z_OBJ_P(object);
                    701: 
1.1.1.2 ! misho     702:        if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
1.1       misho     703:                tmp_member = *member;
                    704:                zval_copy_ctor(&tmp_member);
                    705:                convert_to_string(&tmp_member);
                    706:                member = &tmp_member;
1.1.1.2 ! misho     707:                key = NULL;
1.1       misho     708:        }
                    709: 
                    710: #if DEBUG_OBJECT_HANDLERS
                    711:        fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
                    712: #endif
                    713: 
1.1.1.2 ! misho     714:        property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC);
1.1       misho     715: 
1.1.1.2 ! misho     716:        if (UNEXPECTED(!property_info) ||
        !           717:            ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
        !           718:             property_info->offset >= 0) ?
        !           719:                (zobj->properties ?
        !           720:                    ((retval = (zval**)zobj->properties_table[property_info->offset]) == NULL) :
        !           721:                    (*(retval = &zobj->properties_table[property_info->offset]) == NULL)) :
        !           722:                (UNEXPECTED(!zobj->properties) ||
        !           723:                  UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)))) {
1.1       misho     724:                zval *new_zval;
                    725:                zend_guard *guard;
                    726: 
                    727:                if (!zobj->ce->__get ||
                    728:                        zend_get_property_guard(zobj, property_info, member, &guard) != SUCCESS ||
                    729:                        (property_info && guard->in_get)) {
                    730:                        /* we don't have access controls - will just add it */
                    731:                        new_zval = &EG(uninitialized_zval);
                    732: 
                    733: /*                     zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member)); */
                    734:                        Z_ADDREF_P(new_zval);
1.1.1.2 ! misho     735:                        if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
        !           736:                            property_info->offset >= 0) {
        !           737:                                if (!zobj->properties) {
        !           738:                                        zobj->properties_table[property_info->offset] = new_zval;
        !           739:                                        retval = &zobj->properties_table[property_info->offset];
        !           740:                                } else if (zobj->properties_table[property_info->offset]) {
        !           741:                                        *(zval**)zobj->properties_table[property_info->offset] = new_zval;
        !           742:                                        retval = (zval**)zobj->properties_table[property_info->offset];
        !           743:                                } else {
        !           744:                                        zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]);
        !           745:                                        retval = (zval**)zobj->properties_table[property_info->offset];
        !           746:                                }
        !           747:                        } else {
        !           748:                                if (!zobj->properties) {
        !           749:                                        rebuild_object_properties(zobj);
        !           750:                                }
        !           751:                                zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &new_zval, sizeof(zval *), (void **) &retval);
        !           752:                        }
1.1       misho     753:                } else {
                    754:                        /* we do have getter - fail and let it try again with usual get/set */
                    755:                        retval = NULL;
                    756:                }
                    757:        }
1.1.1.2 ! misho     758:        if (UNEXPECTED(member == &tmp_member)) {
1.1       misho     759:                zval_dtor(member);
                    760:        }
                    761:        return retval;
                    762: }
                    763: /* }}} */
                    764: 
1.1.1.2 ! misho     765: static void zend_std_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho     766: {
                    767:        zend_object *zobj;
                    768:        zval *tmp_member = NULL;
                    769:        zend_property_info *property_info;
                    770: 
                    771:        zobj = Z_OBJ_P(object);
                    772: 
1.1.1.2 ! misho     773:        if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
1.1       misho     774:                ALLOC_ZVAL(tmp_member);
                    775:                *tmp_member = *member;
                    776:                INIT_PZVAL(tmp_member);
                    777:                zval_copy_ctor(tmp_member);
                    778:                convert_to_string(tmp_member);
                    779:                member = tmp_member;
1.1.1.2 ! misho     780:                key = NULL;
1.1       misho     781:        }
                    782: 
1.1.1.2 ! misho     783:        property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__unset != NULL), key TSRMLS_CC);
1.1       misho     784: 
1.1.1.2 ! misho     785:        if (EXPECTED(property_info != NULL) &&
        !           786:            EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && 
        !           787:            !zobj->properties &&
        !           788:            property_info->offset >= 0 &&
        !           789:            EXPECTED(zobj->properties_table[property_info->offset] != NULL)) {
        !           790:                zval_ptr_dtor(&zobj->properties_table[property_info->offset]);
        !           791:                zobj->properties_table[property_info->offset] = NULL;
        !           792:        } else if (UNEXPECTED(!property_info) ||
        !           793:                   !zobj->properties ||
        !           794:                   UNEXPECTED(zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE)) {
1.1       misho     795:                zend_guard *guard = NULL;
                    796: 
                    797:                if (zobj->ce->__unset &&
                    798:                    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
                    799:                    !guard->in_unset) {
                    800:                        /* have unseter - try with it! */
                    801:                        Z_ADDREF_P(object);
                    802:                        if (PZVAL_IS_REF(object)) {
                    803:                                SEPARATE_ZVAL(&object);
                    804:                        }
                    805:                        guard->in_unset = 1; /* prevent circular unsetting */
                    806:                        zend_std_call_unsetter(object, member TSRMLS_CC);
                    807:                        guard->in_unset = 0;
                    808:                        zval_ptr_dtor(&object);
                    809:                } else if (zobj->ce->__unset && guard && guard->in_unset == 1) {
                    810:                        if (Z_STRVAL_P(member)[0] == '\0') {
                    811:                                if (Z_STRLEN_P(member) == 0) {
                    812:                                        zend_error(E_ERROR, "Cannot access empty property");
                    813:                                } else {
                    814:                                        zend_error(E_ERROR, "Cannot access property started with '\\0'");
                    815:                                }
                    816:                        }
                    817:                }
1.1.1.2 ! misho     818:        } else if (EXPECTED(property_info != NULL) && 
        !           819:                   EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && 
        !           820:                   property_info->offset >= 0) {
        !           821:                zobj->properties_table[property_info->offset] = NULL;
1.1       misho     822:        }
                    823: 
1.1.1.2 ! misho     824:        if (UNEXPECTED(tmp_member != NULL)) {
1.1       misho     825:                zval_ptr_dtor(&tmp_member);
                    826:        }
                    827: }
                    828: /* }}} */
                    829: 
                    830: static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
                    831: {
                    832:        zend_class_entry *ce = Z_OBJCE_P(object);
                    833: 
                    834:        if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
                    835:                SEPARATE_ARG_IF_REF(offset);
                    836:                zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", NULL, offset);
                    837:                zval_ptr_dtor(&offset);
                    838:        } else {
1.1.1.2 ! misho     839:                zend_error_noreturn(E_ERROR, "Cannot use object of type %s as array", ce->name);
1.1       misho     840:        }
                    841: }
                    842: /* }}} */
                    843: 
                    844: ZEND_API void zend_std_call_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
                    845: {
                    846:        zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;
                    847:        zval *method_name_ptr, *method_args_ptr;
                    848:        zval *method_result_ptr = NULL;
                    849:        zend_class_entry *ce = Z_OBJCE_P(this_ptr);
                    850: 
                    851:        ALLOC_ZVAL(method_args_ptr);
                    852:        INIT_PZVAL(method_args_ptr);
                    853:        array_init_size(method_args_ptr, ZEND_NUM_ARGS());
                    854: 
1.1.1.2 ! misho     855:        if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE)) {
1.1       misho     856:                zval_dtor(method_args_ptr);
1.1.1.2 ! misho     857:                zend_error_noreturn(E_ERROR, "Cannot get arguments for __call");
1.1       misho     858:                RETURN_FALSE;
                    859:        }
                    860: 
                    861:        ALLOC_ZVAL(method_name_ptr);
                    862:        INIT_PZVAL(method_name_ptr);
                    863:        ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */
                    864: 
                    865:        /* __call handler is called with two arguments:
                    866:           method name
                    867:           array of method parameters
                    868: 
                    869:        */
                    870:        zend_call_method_with_2_params(&this_ptr, ce, &ce->__call, ZEND_CALL_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
                    871: 
                    872:        if (method_result_ptr) {
                    873:                if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) {
                    874:                        RETVAL_ZVAL(method_result_ptr, 1, 1);
                    875:                } else {
                    876:                        RETVAL_ZVAL(method_result_ptr, 0, 1);
                    877:                }
                    878:        }
                    879: 
                    880:        /* now destruct all auxiliaries */
                    881:        zval_ptr_dtor(&method_args_ptr);
                    882:        zval_ptr_dtor(&method_name_ptr);
                    883: 
                    884:        /* destruct the function also, then - we have allocated it in get_method */
                    885:        efree(func);
                    886: }
                    887: /* }}} */
                    888: 
                    889: /* Ensures that we're allowed to call a private method.
                    890:  * Returns the function address that should be called, or NULL
                    891:  * if no such function exists.
                    892:  */
1.1.1.2 ! misho     893: static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen, ulong hash_value TSRMLS_DC) /* {{{ */
1.1       misho     894: {
                    895:        if (!ce) {
                    896:                return 0;
                    897:        }
                    898: 
                    899:        /* We may call a private function if:
                    900:         * 1.  The class of our object is the same as the scope, and the private
                    901:         *     function (EX(fbc)) has the same scope.
                    902:         * 2.  One of our parent classes are the same as the scope, and it contains
                    903:         *     a private function with the same name that has the same scope.
                    904:         */
                    905:        if (fbc->common.scope == ce && EG(scope) == ce) {
                    906:                /* rule #1 checks out ok, allow the function call */
                    907:                return fbc;
                    908:        }
                    909: 
                    910: 
                    911:        /* Check rule #2 */
                    912:        ce = ce->parent;
                    913:        while (ce) {
                    914:                if (ce == EG(scope)) {
1.1.1.2 ! misho     915:                        if (zend_hash_quick_find(&ce->function_table, function_name_strval, function_name_strlen+1, hash_value, (void **) &fbc)==SUCCESS
1.1       misho     916:                                && fbc->op_array.fn_flags & ZEND_ACC_PRIVATE
                    917:                                && fbc->common.scope == EG(scope)) {
                    918:                                return fbc;
                    919:                        }
                    920:                        break;
                    921:                }
                    922:                ce = ce->parent;
                    923:        }
                    924:        return NULL;
                    925: }
                    926: /* }}} */
                    927: 
                    928: ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, char *function_name_strval, int function_name_strlen TSRMLS_DC) /* {{{ */
                    929: {
1.1.1.2 ! misho     930:        return zend_check_private_int(fbc, ce, function_name_strval, function_name_strlen, zend_hash_func(function_name_strval, function_name_strlen+1) TSRMLS_CC) != NULL;
1.1       misho     931: }
                    932: /* }}} */
                    933: 
                    934: /* Ensures that we're allowed to call a protected method.
                    935:  */
                    936: ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) /* {{{ */
                    937: {
                    938:        zend_class_entry *fbc_scope = ce;
                    939: 
                    940:        /* Is the context that's calling the function, the same as one of
                    941:         * the function's parents?
                    942:         */
                    943:        while (fbc_scope) {
                    944:                if (fbc_scope==scope) {
                    945:                        return 1;
                    946:                }
                    947:                fbc_scope = fbc_scope->parent;
                    948:        }
                    949: 
                    950:        /* Is the function's scope the same as our current object context,
                    951:         * or any of the parents of our context?
                    952:         */
                    953:        while (scope) {
                    954:                if (scope==ce) {
                    955:                        return 1;
                    956:                }
                    957:                scope = scope->parent;
                    958:        }
                    959:        return 0;
                    960: }
                    961: /* }}} */
                    962: 
                    963: static inline zend_class_entry * zend_get_function_root_class(zend_function *fbc) /* {{{ */
                    964: {
                    965:        return fbc->common.prototype ? fbc->common.prototype->common.scope : fbc->common.scope;
                    966: }
                    967: /* }}} */
                    968: 
                    969: static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */
                    970: {
                    971:        zend_internal_function *call_user_call = emalloc(sizeof(zend_internal_function));
                    972:        call_user_call->type = ZEND_INTERNAL_FUNCTION;
1.1.1.2 ! misho     973:        call_user_call->module = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
1.1       misho     974:        call_user_call->handler = zend_std_call_user_call;
                    975:        call_user_call->arg_info = NULL;
                    976:        call_user_call->num_args = 0;
                    977:        call_user_call->scope = ce;
                    978:        call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
                    979:        call_user_call->function_name = estrndup(method_name, method_len);
                    980: 
                    981:        return (union _zend_function *)call_user_call;
                    982: }
                    983: /* }}} */
                    984: 
1.1.1.2 ! misho     985: static union _zend_function *zend_std_get_method(zval **object_ptr, char *method_name, int method_len, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho     986: {
                    987:        zend_function *fbc;
                    988:        zval *object = *object_ptr;
1.1.1.2 ! misho     989:        zend_object *zobj = Z_OBJ_P(object);
        !           990:        ulong hash_value;
        !           991:        char *lc_method_name;
1.1       misho     992:        ALLOCA_FLAG(use_heap)
                    993: 
1.1.1.2 ! misho     994:        if (EXPECTED(key != NULL)) {
        !           995:                lc_method_name = Z_STRVAL(key->constant);
        !           996:                hash_value = key->hash_value;
        !           997:        } else {
        !           998:                lc_method_name = do_alloca(method_len+1, use_heap);
        !           999:                /* Create a zend_copy_str_tolower(dest, src, src_length); */
        !          1000:                zend_str_tolower_copy(lc_method_name, method_name, method_len);
        !          1001:                hash_value = zend_hash_func(lc_method_name, method_len+1);
        !          1002:        }
1.1       misho    1003: 
1.1.1.2 ! misho    1004:        if (UNEXPECTED(zend_hash_quick_find(&zobj->ce->function_table, lc_method_name, method_len+1, hash_value, (void **)&fbc) == FAILURE)) {
        !          1005:                if (UNEXPECTED(!key)) {
        !          1006:                        free_alloca(lc_method_name, use_heap);
        !          1007:                }
1.1       misho    1008:                if (zobj->ce->__call) {
                   1009:                        return zend_get_user_call_function(zobj->ce, method_name, method_len);
                   1010:                } else {
                   1011:                        return NULL;
                   1012:                }
                   1013:        }
                   1014: 
                   1015:        /* Check access level */
                   1016:        if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
                   1017:                zend_function *updated_fbc;
                   1018: 
                   1019:                /* Ensure that if we're calling a private function, we're allowed to do so.
                   1020:                 * If we're not and __call() handler exists, invoke it, otherwise error out.
                   1021:                 */
1.1.1.2 ! misho    1022:                updated_fbc = zend_check_private_int(fbc, Z_OBJ_HANDLER_P(object, get_class_entry)(object TSRMLS_CC), lc_method_name, method_len, hash_value TSRMLS_CC);
        !          1023:                if (EXPECTED(updated_fbc != NULL)) {
1.1       misho    1024:                        fbc = updated_fbc;
                   1025:                } else {
                   1026:                        if (zobj->ce->__call) {
                   1027:                                fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
                   1028:                        } else {
1.1.1.2 ! misho    1029:                                zend_error_noreturn(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 : "");
1.1       misho    1030:                        }
                   1031:                }
                   1032:        } else {
                   1033:                /* Ensure that we haven't overridden a private function and end up calling
                   1034:                 * the overriding public function...
                   1035:                 */
                   1036:                if (EG(scope) &&
                   1037:                    is_derived_class(fbc->common.scope, EG(scope)) &&
                   1038:                    fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
                   1039:                        zend_function *priv_fbc;
                   1040: 
1.1.1.2 ! misho    1041:                        if (zend_hash_quick_find(&EG(scope)->function_table, lc_method_name, method_len+1, hash_value, (void **) &priv_fbc)==SUCCESS
1.1       misho    1042:                                && priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
                   1043:                                && priv_fbc->common.scope == EG(scope)) {
                   1044:                                fbc = priv_fbc;
                   1045:                        }
                   1046:                }
                   1047:                if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
                   1048:                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                   1049:                         * If we're not and __call() handler exists, invoke it, otherwise error out.
                   1050:                         */
1.1.1.2 ! misho    1051:                        if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), EG(scope)))) {
1.1       misho    1052:                                if (zobj->ce->__call) {
                   1053:                                        fbc = zend_get_user_call_function(zobj->ce, method_name, method_len);
                   1054:                                } else {
1.1.1.2 ! misho    1055:                                        zend_error_noreturn(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 : "");
1.1       misho    1056:                                }
                   1057:                        }
                   1058:                }
                   1059:        }
                   1060: 
1.1.1.2 ! misho    1061:        if (UNEXPECTED(!key)) {
        !          1062:                free_alloca(lc_method_name, use_heap);
        !          1063:        }
1.1       misho    1064:        return fbc;
                   1065: }
                   1066: /* }}} */
                   1067: 
                   1068: ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ */
                   1069: {
                   1070:        zend_internal_function *func = (zend_internal_function *)EG(current_execute_data)->function_state.function;
                   1071:        zval *method_name_ptr, *method_args_ptr;
                   1072:        zval *method_result_ptr = NULL;
                   1073:        zend_class_entry *ce = EG(scope);
                   1074: 
                   1075:        ALLOC_ZVAL(method_args_ptr);
                   1076:        INIT_PZVAL(method_args_ptr);
                   1077:        array_init_size(method_args_ptr, ZEND_NUM_ARGS());
                   1078: 
1.1.1.2 ! misho    1079:        if (UNEXPECTED(zend_copy_parameters_array(ZEND_NUM_ARGS(), method_args_ptr TSRMLS_CC) == FAILURE)) {
1.1       misho    1080:                zval_dtor(method_args_ptr);
1.1.1.2 ! misho    1081:                zend_error_noreturn(E_ERROR, "Cannot get arguments for " ZEND_CALLSTATIC_FUNC_NAME);
1.1       misho    1082:                RETURN_FALSE;
                   1083:        }
                   1084: 
                   1085:        ALLOC_ZVAL(method_name_ptr);
                   1086:        INIT_PZVAL(method_name_ptr);
                   1087:        ZVAL_STRING(method_name_ptr, func->function_name, 0); /* no dup - it's a copy */
                   1088: 
                   1089:        /* __callStatic handler is called with two arguments:
                   1090:           method name
                   1091:           array of method parameters
                   1092:        */
                   1093:        zend_call_method_with_2_params(NULL, ce, &ce->__callstatic, ZEND_CALLSTATIC_FUNC_NAME, &method_result_ptr, method_name_ptr, method_args_ptr);
                   1094: 
                   1095:        if (method_result_ptr) {
                   1096:                if (Z_ISREF_P(method_result_ptr) || Z_REFCOUNT_P(method_result_ptr) > 1) {
                   1097:                        RETVAL_ZVAL(method_result_ptr, 1, 1);
                   1098:                } else {
                   1099:                        RETVAL_ZVAL(method_result_ptr, 0, 1);
                   1100:                }
                   1101:        }
                   1102: 
                   1103:        /* now destruct all auxiliaries */
                   1104:        zval_ptr_dtor(&method_args_ptr);
                   1105:        zval_ptr_dtor(&method_name_ptr);
                   1106: 
                   1107:        /* destruct the function also, then - we have allocated it in get_method */
                   1108:        efree(func);
                   1109: }
                   1110: /* }}} */
                   1111: 
                   1112: static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, const char *method_name, int method_len) /* {{{ */
                   1113: {
                   1114:        zend_internal_function *callstatic_user_call = emalloc(sizeof(zend_internal_function));
                   1115:        callstatic_user_call->type     = ZEND_INTERNAL_FUNCTION;
1.1.1.2 ! misho    1116:        callstatic_user_call->module   = (ce->type == ZEND_INTERNAL_CLASS) ? ce->info.internal.module : NULL;
1.1       misho    1117:        callstatic_user_call->handler  = zend_std_callstatic_user_call;
                   1118:        callstatic_user_call->arg_info = NULL;
                   1119:        callstatic_user_call->num_args = 0;
                   1120:        callstatic_user_call->scope    = ce;
                   1121:        callstatic_user_call->fn_flags = ZEND_ACC_STATIC | ZEND_ACC_PUBLIC | ZEND_ACC_CALL_VIA_HANDLER;
                   1122:        callstatic_user_call->function_name = estrndup(method_name, method_len);
                   1123: 
                   1124:        return (zend_function *)callstatic_user_call;
                   1125: }
                   1126: /* }}} */
                   1127: 
                   1128: /* This is not (yet?) in the API, but it belongs in the built-in objects callbacks */
                   1129: 
1.1.1.2 ! misho    1130: ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, const char *function_name_strval, int function_name_strlen, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho    1131: {
                   1132:        zend_function *fbc = NULL;
                   1133:        char *lc_class_name, *lc_function_name = NULL;
1.1.1.2 ! misho    1134:        ulong hash_value;
        !          1135:        ALLOCA_FLAG(use_heap)
1.1       misho    1136: 
1.1.1.2 ! misho    1137:        if (EXPECTED(key != NULL)) {
        !          1138:                lc_function_name = Z_STRVAL(key->constant);
        !          1139:                hash_value = key->hash_value;
        !          1140:        } else {
        !          1141:                lc_function_name = do_alloca(function_name_strlen+1, use_heap);
        !          1142:                /* Create a zend_copy_str_tolower(dest, src, src_length); */
        !          1143:                zend_str_tolower_copy(lc_function_name, function_name_strval, function_name_strlen);
        !          1144:                hash_value = zend_hash_func(lc_function_name, function_name_strlen+1);
        !          1145:        }
        !          1146:        
1.1       misho    1147:        if (function_name_strlen == ce->name_length && ce->constructor) {
                   1148:                lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
                   1149:                /* Only change the method to the constructor if the constructor isn't called __construct
                   1150:                 * we check for __ so we can be binary safe for lowering, we should use ZEND_CONSTRUCTOR_FUNC_NAME
                   1151:                 */
                   1152:                if (!memcmp(lc_class_name, lc_function_name, function_name_strlen) && memcmp(ce->constructor->common.function_name, "__", sizeof("__") - 1)) {
                   1153:                        fbc = ce->constructor;
                   1154:                }
                   1155:                efree(lc_class_name);
                   1156:        }
1.1.1.2 ! misho    1157:        if (EXPECTED(!fbc) &&
        !          1158:            UNEXPECTED(zend_hash_quick_find(&ce->function_table, lc_function_name, function_name_strlen+1, hash_value, (void **) &fbc)==FAILURE)) {
        !          1159:                if (UNEXPECTED(!key)) {
        !          1160:                        free_alloca(lc_function_name, use_heap);
        !          1161:                }
1.1       misho    1162: 
                   1163:                if (ce->__call &&
                   1164:                    EG(This) &&
                   1165:                    Z_OBJ_HT_P(EG(This))->get_class_entry &&
                   1166:                    instanceof_function(Z_OBJCE_P(EG(This)), ce TSRMLS_CC)) {
                   1167:                        return zend_get_user_call_function(ce, function_name_strval, function_name_strlen);
                   1168:                } else if (ce->__callstatic) {
                   1169:                        return zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
                   1170:                } else {
                   1171:                        return NULL;
                   1172:                }
                   1173:        }
                   1174: 
                   1175: #if MBO_0
                   1176:        /* right now this function is used for non static method lookup too */
                   1177:        /* Is the function static */
1.1.1.2 ! misho    1178:        if (UNEXPECTED(!(fbc->common.fn_flags & ZEND_ACC_STATIC))) {
        !          1179:                zend_error_noreturn(E_ERROR, "Cannot call non static method %s::%s() without object", ZEND_FN_SCOPE_NAME(fbc), fbc->common.function_name);
1.1       misho    1180:        }
                   1181: #endif 
                   1182:        if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
                   1183:                /* No further checks necessary, most common case */
                   1184:        } else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
                   1185:                zend_function *updated_fbc;
                   1186: 
                   1187:                /* Ensure that if we're calling a private function, we're allowed to do so.
                   1188:                 */
1.1.1.2 ! misho    1189:                updated_fbc = zend_check_private_int(fbc, EG(scope), lc_function_name, function_name_strlen, hash_value TSRMLS_CC);
        !          1190:                if (EXPECTED(updated_fbc != NULL)) {
1.1       misho    1191:                        fbc = updated_fbc;
                   1192:                } else {
                   1193:                        if (ce->__callstatic) {
1.1.1.2 ! misho    1194:                                fbc = zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
        !          1195:                        } else {
        !          1196:                                zend_error_noreturn(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 : "");
1.1       misho    1197:                        }
                   1198:                }
                   1199:        } else if ((fbc->common.fn_flags & ZEND_ACC_PROTECTED)) {
                   1200:                /* Ensure that if we're calling a protected function, we're allowed to do so.
                   1201:                 */
1.1.1.2 ! misho    1202:                if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), EG(scope)))) {
1.1       misho    1203:                        if (ce->__callstatic) {
1.1.1.2 ! misho    1204:                                fbc = zend_get_user_callstatic_function(ce, function_name_strval, function_name_strlen);
        !          1205:                        } else {
        !          1206:                                zend_error_noreturn(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 : "");
1.1       misho    1207:                        }
                   1208:                }
                   1209:        }
                   1210: 
1.1.1.2 ! misho    1211:        if (UNEXPECTED(!key)) {
        !          1212:                free_alloca(lc_function_name, use_heap);
        !          1213:        }
        !          1214: 
1.1       misho    1215:        return fbc;
                   1216: }
                   1217: /* }}} */
                   1218: 
1.1.1.2 ! misho    1219: ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, zend_bool silent, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho    1220: {
                   1221:        zend_property_info *property_info;
1.1.1.2 ! misho    1222:        ulong hash_value;
        !          1223:        
        !          1224:        if (UNEXPECTED(!key) ||
        !          1225:            (property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) == NULL) {
        !          1226:                if (EXPECTED(key != NULL)) {
        !          1227:                        hash_value = key->hash_value;
        !          1228:                } else {
        !          1229:                        hash_value = zend_hash_func(property_name, property_name_len+1);
        !          1230:                }
1.1       misho    1231: 
1.1.1.2 ! misho    1232:                if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+1, hash_value, (void **) &property_info)==FAILURE)) {
        !          1233:                        if (!silent) {
        !          1234:                                zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
        !          1235:                        }
        !          1236:                        return NULL;
        !          1237:                }
1.1       misho    1238: 
                   1239: #if DEBUG_OBJECT_HANDLERS
1.1.1.2 ! misho    1240:                zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags));
1.1       misho    1241: #endif
                   1242: 
1.1.1.2 ! misho    1243:                if (UNEXPECTED(!zend_verify_property_access(property_info, ce TSRMLS_CC))) {
        !          1244:                        if (!silent) {
        !          1245:                                zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
        !          1246:                        }
        !          1247:                        return NULL;
1.1       misho    1248:                }
                   1249: 
1.1.1.2 ! misho    1250:                if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) {
        !          1251:                        if (!silent) {
        !          1252:                                zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
        !          1253:                        }
        !          1254:                        return NULL;
        !          1255:                }
1.1       misho    1256: 
1.1.1.2 ! misho    1257:                zend_update_class_constants(ce TSRMLS_CC);
1.1       misho    1258: 
1.1.1.2 ! misho    1259:                if (EXPECTED(key != NULL)) {
        !          1260:                        CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info);
1.1       misho    1261:                }
                   1262:        }
                   1263: 
1.1.1.2 ! misho    1264:        return &CE_STATIC_MEMBERS(ce)[property_info->offset];
1.1       misho    1265: }
                   1266: /* }}} */
                   1267: 
1.1.1.2 ! misho    1268: ZEND_API zend_bool zend_std_unset_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho    1269: {
1.1.1.2 ! misho    1270:        zend_error_noreturn(E_ERROR, "Attempt to unset static property %s::$%s", ce->name, property_name);
1.1       misho    1271:        return 0;
                   1272: }
                   1273: /* }}} */
                   1274: 
                   1275: ZEND_API union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC) /* {{{ */
                   1276: {
                   1277:        zend_object *zobj = Z_OBJ_P(object);
                   1278:        zend_function *constructor = zobj->ce->constructor;
                   1279: 
                   1280:        if (constructor) {
                   1281:                if (constructor->op_array.fn_flags & ZEND_ACC_PUBLIC) {
                   1282:                        /* No further checks necessary */
                   1283:                } else if (constructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
                   1284:                        /* Ensure that if we're calling a private function, we're allowed to do so.
                   1285:                         */
1.1.1.2 ! misho    1286:                        if (UNEXPECTED(constructor->common.scope != EG(scope))) {
1.1       misho    1287:                                if (EG(scope)) {
1.1.1.2 ! misho    1288:                                        zend_error_noreturn(E_ERROR, "Call to private %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
1.1       misho    1289:                                } else {
1.1.1.2 ! misho    1290:                                        zend_error_noreturn(E_ERROR, "Call to private %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
1.1       misho    1291:                                }
                   1292:                        }
                   1293:                } else if ((constructor->common.fn_flags & ZEND_ACC_PROTECTED)) {
                   1294:                        /* Ensure that if we're calling a protected function, we're allowed to do so.
                   1295:                         * Constructors only have prototype if they are defined by an interface but
                   1296:                         * it is the compilers responsibility to take care of the prototype.
                   1297:                         */
1.1.1.2 ! misho    1298:                        if (UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor), EG(scope)))) {
1.1       misho    1299:                                if (EG(scope)) {
1.1.1.2 ! misho    1300:                                        zend_error_noreturn(E_ERROR, "Call to protected %s::%s() from context '%s'", constructor->common.scope->name, constructor->common.function_name, EG(scope)->name);
1.1       misho    1301:                                } else {
1.1.1.2 ! misho    1302:                                        zend_error_noreturn(E_ERROR, "Call to protected %s::%s() from invalid context", constructor->common.scope->name, constructor->common.function_name);
1.1       misho    1303:                                }
                   1304:                        }
                   1305:                }
                   1306:        }
                   1307: 
                   1308:        return constructor;
                   1309: }
                   1310: /* }}} */
                   1311: 
                   1312: int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC);
                   1313: 
                   1314: static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
                   1315: {
                   1316:        zend_object *zobj1, *zobj2;
                   1317: 
                   1318:        zobj1 = Z_OBJ_P(o1);
                   1319:        zobj2 = Z_OBJ_P(o2);
                   1320: 
                   1321:        if (zobj1->ce != zobj2->ce) {
                   1322:                return 1; /* different classes */
                   1323:        }
1.1.1.2 ! misho    1324:        if (!zobj1->properties && !zobj2->properties) {
        !          1325:                int i;
        !          1326:                for (i = 0; i < zobj1->ce->default_properties_count; i++) {
        !          1327:                        if (zobj1->properties_table[i]) {
        !          1328:                                if (zobj2->properties_table[i]) {
        !          1329:                                        zval result;
        !          1330: 
        !          1331:                                        if (compare_function(&result, zobj1->properties_table[i], zobj2->properties_table[i] TSRMLS_CC)==FAILURE) {
        !          1332:                                                return 1;
        !          1333:                                        }
        !          1334:                                        if (Z_LVAL(result) != 0) {
        !          1335:                                                return Z_LVAL(result);
        !          1336:                                        }
        !          1337:                                } else {
        !          1338:                                        return 1;
        !          1339:                                }
        !          1340:                        } else {
        !          1341:                                if (zobj2->properties_table[i]) {
        !          1342:                                        return 1;
        !          1343:                                } else {
        !          1344:                                        return 0;
        !          1345:                                }
        !          1346:                        }
        !          1347:                }
        !          1348:                return 0;
        !          1349:        } else {
        !          1350:                if (!zobj1->properties) {
        !          1351:                        rebuild_object_properties(zobj1);
        !          1352:                }
        !          1353:                if (!zobj2->properties) {
        !          1354:                        rebuild_object_properties(zobj2);
        !          1355:                }
        !          1356:                return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC);
        !          1357:        }
1.1       misho    1358: }
                   1359: /* }}} */
                   1360: 
1.1.1.2 ! misho    1361: static int zend_std_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1       misho    1362: {
                   1363:        zend_object *zobj;
                   1364:        int result;
1.1.1.2 ! misho    1365:        zval **value = NULL;
1.1       misho    1366:        zval *tmp_member = NULL;
                   1367:        zend_property_info *property_info;
                   1368: 
                   1369:        zobj = Z_OBJ_P(object);
                   1370: 
1.1.1.2 ! misho    1371:        if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
1.1       misho    1372:                ALLOC_ZVAL(tmp_member);
                   1373:                *tmp_member = *member;
                   1374:                INIT_PZVAL(tmp_member);
                   1375:                zval_copy_ctor(tmp_member);
                   1376:                convert_to_string(tmp_member);
                   1377:                member = tmp_member;
1.1.1.2 ! misho    1378:                key = NULL;
1.1       misho    1379:        }
                   1380: 
                   1381: #if DEBUG_OBJECT_HANDLERS
                   1382:        fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
                   1383: #endif
                   1384: 
1.1.1.2 ! misho    1385:        property_info = zend_get_property_info_quick(zobj->ce, member, 1, key TSRMLS_CC);
1.1       misho    1386: 
1.1.1.2 ! misho    1387:        if (UNEXPECTED(!property_info) ||
        !          1388:            ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
        !          1389:             property_info->offset >= 0) ?
        !          1390:                (zobj->properties ?
        !          1391:                    ((value = (zval**)zobj->properties_table[property_info->offset]) == NULL) :
        !          1392:                    (*(value = &zobj->properties_table[property_info->offset]) == NULL)) :
        !          1393:                (UNEXPECTED(!zobj->properties) ||
        !          1394:                  UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &value) == FAILURE)))) {
1.1       misho    1395:                zend_guard *guard;
                   1396: 
                   1397:                result = 0;
                   1398:                if ((has_set_exists != 2) &&
                   1399:                    zobj->ce->__isset &&
                   1400:                    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
                   1401:                    !guard->in_isset) {
                   1402:                        zval *rv;
                   1403: 
                   1404:                        /* have issetter - try with it! */
                   1405:                        Z_ADDREF_P(object);
                   1406:                        if (PZVAL_IS_REF(object)) {
                   1407:                                SEPARATE_ZVAL(&object);
                   1408:                        }
                   1409:                        guard->in_isset = 1; /* prevent circular getting */
                   1410:                        rv = zend_std_call_issetter(object, member TSRMLS_CC);
                   1411:                        if (rv) {
                   1412:                                result = zend_is_true(rv);
                   1413:                                zval_ptr_dtor(&rv);
                   1414:                                if (has_set_exists && result) {
1.1.1.2 ! misho    1415:                                        if (EXPECTED(!EG(exception)) && zobj->ce->__get && !guard->in_get) {
1.1       misho    1416:                                                guard->in_get = 1;
                   1417:                                                rv = zend_std_call_getter(object, member TSRMLS_CC);
                   1418:                                                guard->in_get = 0;
                   1419:                                                if (rv) {
                   1420:                                                        Z_ADDREF_P(rv);
                   1421:                                                        result = i_zend_is_true(rv);
                   1422:                                                        zval_ptr_dtor(&rv);
                   1423:                                                } else {
                   1424:                                                        result = 0;
                   1425:                                                }
                   1426:                                        } else {
                   1427:                                                result = 0;
                   1428:                                        }
                   1429:                                }
                   1430:                        }
                   1431:                        guard->in_isset = 0;
                   1432:                        zval_ptr_dtor(&object);
                   1433:                }
                   1434:        } else {
                   1435:                switch (has_set_exists) {
                   1436:                case 0:
                   1437:                        result = (Z_TYPE_PP(value) != IS_NULL);
                   1438:                        break;
                   1439:                default:
                   1440:                        result = zend_is_true(*value);
                   1441:                        break;
                   1442:                case 2:
                   1443:                        result = 1;
                   1444:                        break;
                   1445:                }
                   1446:        }
                   1447: 
1.1.1.2 ! misho    1448:        if (UNEXPECTED(tmp_member != NULL)) {
1.1       misho    1449:                zval_ptr_dtor(&tmp_member);
                   1450:        }
                   1451:        return result;
                   1452: }
                   1453: /* }}} */
                   1454: 
                   1455: zend_class_entry *zend_std_object_get_class(const zval *object TSRMLS_DC) /* {{{ */
                   1456: {
                   1457:        zend_object *zobj;
                   1458:        zobj = Z_OBJ_P(object);
                   1459: 
                   1460:        return zobj->ce;
                   1461: }
                   1462: /* }}} */
                   1463: 
1.1.1.2 ! misho    1464: int zend_std_object_get_class_name(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC) /* {{{ */
1.1       misho    1465: {
                   1466:        zend_object *zobj;
                   1467:        zend_class_entry *ce;
                   1468:        zobj = Z_OBJ_P(object);
                   1469: 
                   1470:        if (parent) {
                   1471:                if (!zobj->ce->parent) {
                   1472:                        return FAILURE;
                   1473:                }
                   1474:                ce = zobj->ce->parent;
                   1475:        } else {
                   1476:                ce = zobj->ce;
                   1477:        }
                   1478: 
                   1479:        *class_name_len = ce->name_length;
                   1480:        *class_name = estrndup(ce->name, ce->name_length);
                   1481:        return SUCCESS;
                   1482: }
                   1483: /* }}} */
                   1484: 
                   1485: ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
                   1486: {
                   1487:        zval *retval;
                   1488:        zend_class_entry *ce;
                   1489: 
                   1490:        switch (type) {
                   1491:                case IS_STRING:
                   1492:                        ce = Z_OBJCE_P(readobj);
                   1493:                        if (ce->__tostring &&
                   1494:                                (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring", &retval) || EG(exception))) {
1.1.1.2 ! misho    1495:                                if (UNEXPECTED(EG(exception) != NULL)) {
1.1       misho    1496:                                        if (retval) {
                   1497:                                                zval_ptr_dtor(&retval);
                   1498:                                        }
1.1.1.2 ! misho    1499:                                        zend_error_noreturn(E_ERROR, "Method %s::__toString() must not throw an exception", ce->name);
1.1       misho    1500:                                        return FAILURE;
                   1501:                                }
1.1.1.2 ! misho    1502:                                if (EXPECTED(Z_TYPE_P(retval) == IS_STRING)) {
1.1       misho    1503:                                        INIT_PZVAL(writeobj);
                   1504:                                        if (readobj == writeobj) {
                   1505:                                                zval_dtor(readobj);
                   1506:                                        }
                   1507:                                        ZVAL_ZVAL(writeobj, retval, 1, 1);
                   1508:                                        if (Z_TYPE_P(writeobj) != type) {
                   1509:                                                convert_to_explicit_type(writeobj, type);
                   1510:                                        }
                   1511:                                        return SUCCESS;
                   1512:                                } else {
                   1513:                                        zval_ptr_dtor(&retval);
                   1514:                                        INIT_PZVAL(writeobj);
                   1515:                                        if (readobj == writeobj) {
                   1516:                                                zval_dtor(readobj);
                   1517:                                        }
                   1518:                                        ZVAL_EMPTY_STRING(writeobj);
                   1519:                                        zend_error(E_RECOVERABLE_ERROR, "Method %s::__toString() must return a string value", ce->name);
                   1520:                                        return SUCCESS;
                   1521:                                }
                   1522:                        }
                   1523:                        return FAILURE;
                   1524:                case IS_BOOL:
                   1525:                        INIT_PZVAL(writeobj);
                   1526:                        ZVAL_BOOL(writeobj, 1);
                   1527:                        return SUCCESS;
                   1528:                case IS_LONG:
                   1529:                        ce = Z_OBJCE_P(readobj);
                   1530:                        zend_error(E_NOTICE, "Object of class %s could not be converted to int", ce->name);
                   1531:                        INIT_PZVAL(writeobj);
                   1532:                        if (readobj == writeobj) {
                   1533:                                zval_dtor(readobj);
                   1534:                        }
                   1535:                        ZVAL_LONG(writeobj, 1);
                   1536:                        return SUCCESS;
                   1537:                case IS_DOUBLE:
                   1538:                        ce = Z_OBJCE_P(readobj);
                   1539:                        zend_error(E_NOTICE, "Object of class %s could not be converted to double", ce->name);
                   1540:                        INIT_PZVAL(writeobj);
                   1541:                        if (readobj == writeobj) {
                   1542:                                zval_dtor(readobj);
                   1543:                        }
                   1544:                        ZVAL_DOUBLE(writeobj, 1);
                   1545:                        return SUCCESS;
                   1546:                default:
                   1547:                        INIT_PZVAL(writeobj);
                   1548:                        Z_TYPE_P(writeobj) = IS_NULL;
                   1549:                        break;
                   1550:        }
                   1551:        return FAILURE;
                   1552: }
                   1553: /* }}} */
                   1554: 
                   1555: int zend_std_get_closure(zval *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval **zobj_ptr TSRMLS_DC) /* {{{ */
                   1556: {
                   1557:        zend_class_entry *ce;
                   1558:        if (Z_TYPE_P(obj) != IS_OBJECT) {
                   1559:                return FAILURE;
                   1560:        }
                   1561: 
                   1562:        ce = Z_OBJCE_P(obj);
                   1563: 
                   1564:        if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME), (void**)fptr_ptr) == FAILURE) {
                   1565:                return FAILURE;
                   1566:        }
                   1567: 
                   1568:        *ce_ptr = ce;
                   1569:        if ((*fptr_ptr)->common.fn_flags & ZEND_ACC_STATIC) {
                   1570:                if (zobj_ptr) {
                   1571:                        *zobj_ptr = NULL;
                   1572:                }
                   1573:        } else {
                   1574:                if (zobj_ptr) {
                   1575:                        *zobj_ptr = obj;
                   1576:                }
                   1577:        }
                   1578:        return SUCCESS;
                   1579: }
                   1580: /* }}} */
                   1581: 
                   1582: ZEND_API zend_object_handlers std_object_handlers = {
                   1583:        zend_objects_store_add_ref,                             /* add_ref */
                   1584:        zend_objects_store_del_ref,                             /* del_ref */
                   1585:        zend_objects_clone_obj,                                 /* clone_obj */
                   1586: 
                   1587:        zend_std_read_property,                                 /* read_property */
                   1588:        zend_std_write_property,                                /* write_property */
                   1589:        zend_std_read_dimension,                                /* read_dimension */
                   1590:        zend_std_write_dimension,                               /* write_dimension */
                   1591:        zend_std_get_property_ptr_ptr,                  /* get_property_ptr_ptr */
                   1592:        NULL,                                                                   /* get */
                   1593:        NULL,                                                                   /* set */
                   1594:        zend_std_has_property,                                  /* has_property */
                   1595:        zend_std_unset_property,                                /* unset_property */
                   1596:        zend_std_has_dimension,                                 /* has_dimension */
                   1597:        zend_std_unset_dimension,                               /* unset_dimension */
                   1598:        zend_std_get_properties,                                /* get_properties */
                   1599:        zend_std_get_method,                                    /* get_method */
                   1600:        NULL,                                                                   /* call_method */
                   1601:        zend_std_get_constructor,                               /* get_constructor */
                   1602:        zend_std_object_get_class,                              /* get_class_entry */
                   1603:        zend_std_object_get_class_name,                 /* get_class_name */
                   1604:        zend_std_compare_objects,                               /* compare_objects */
                   1605:        zend_std_cast_object_tostring,                  /* cast_object */
                   1606:        NULL,                                                                   /* count_elements */
                   1607:        NULL,                                                                   /* get_debug_info */
                   1608:        zend_std_get_closure,                                   /* get_closure */
1.1.1.2 ! misho    1609:        zend_std_get_gc,                                                /* get_gc */
1.1       misho    1610: };
                   1611: 
                   1612: /*
                   1613:  * Local variables:
                   1614:  * tab-width: 4
                   1615:  * c-basic-offset: 4
                   1616:  * indent-tabs-mode: t
                   1617:  * End:
                   1618:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>