Annotation of embedaddon/php/Zend/zend_object_handlers.c, revision 1.1.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>