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

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

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