//讀取屬性
zval *zend_std_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */
{
zend_object *zobj;
zval tmp_member, tmp_object;
zval *retval;
uint32_t property_offset;
uint32_t *guard = NULL;
zobj = Z_OBJ_P(object);
ZVAL_UNDEF(&tmp_member);
if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) {
ZVAL_STR(&tmp_member, zval_get_string(member));
member = &tmp_member;
cache_slot = NULL;
}
#if DEBUG_OBJECT_HANDLERS
fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
#endif
/* make zend_get_property_info silent if we have getter - we may want to use it */
//根據屬性名在zend_class.zend_property_info中查詢zend_property_info,得到屬性值在zend_object中的儲存offset
//zend_get_property_offset()會對屬性的可見性(public、private、protected)進行驗證 ********
property_offset = zend_get_property_offset(zobj->ce, Z_STR_P(member), (type == BP_VAR_IS) || (zobj->ce->__get != NULL), cache_slot);
if (EXPECTED(property_offset != ZEND_WRONG_PROPERTY_OFFSET)) {
if (EXPECTED(property_offset != ZEND_DYNAMIC_PROPERTY_OFFSET)) {
//普通屬性,直接根據offset取到屬性值:((zval*)((char*)(zobj) + offset))
retval = OBJ_PROP(zobj, property_offset);
if (EXPECTED(Z_TYPE_P(retval) != IS_UNDEF)) {
goto exit;
}
} else if (EXPECTED(zobj->properties != NULL)) {
//動態屬性的情況,沒有在類中顯式定義的屬性
retval = zend_hash_find(zobj->properties, Z_STR_P(member));
if (EXPECTED(retval)) goto exit;
}
} else if (UNEXPECTED(EG(exception))) {
retval = &EG(uninitialized_zval);
goto exit;
}
ZVAL_UNDEF(&tmp_object);
/* magic isset */
//沒有找到屬性
//呼叫魔術方法:__isset()
if ((type == BP_VAR_IS) && zobj->ce->__isset) {
zval tmp_result;
guard = zend_get_property_guard(zobj, Z_STR_P(member));
if (!((*guard) & IN_ISSET)) { //
if (Z_TYPE(tmp_member) == IS_UNDEF) {
ZVAL_COPY(&tmp_member, member);
member = &tmp_member;
}
ZVAL_COPY(&tmp_object, object);
ZVAL_UNDEF(&tmp_result);
*guard |= IN_ISSET;
zend_std_call_issetter(&tmp_object, member, &tmp_result);
*guard &= ~IN_ISSET;
if (!zend_is_true(&tmp_result)) {
retval = &EG(uninitialized_zval);
zval_ptr_dtor(&tmp_object);
zval_ptr_dtor(&tmp_result);
goto exit;
}
zval_ptr_dtor(&tmp_result);
}
}
/* magic get */
if (zobj->ce->__get) {
//判斷get的變數名是否已經在__get()中
if (guard == NULL) {
guard = zend_get_property_guard(zobj, Z_STR_P(member));
}
if (!((*guard) & IN_GET)) {
/* have getter - try with it! */
if (Z_TYPE(tmp_object) == IS_UNDEF) {
ZVAL_COPY(&tmp_object, object);
}
*guard |= IN_GET; /* prevent circular getting */
zend_std_call_getter(&tmp_object, member, rv);
*guard &= ~IN_GET;
if (Z_TYPE_P(rv) != IS_UNDEF) {
retval = rv;
if (!Z_ISREF_P(rv) &&
(type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)) {
SEPARATE_ZVAL(rv);
if (UNEXPECTED(Z_TYPE_P(rv) != IS_OBJECT)) {
zend_error(E_NOTICE, "Indirect modification of overloaded property %s::$%s has no effect", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
}
}
} else {
retval = &EG(uninitialized_zval);
}
zval_ptr_dtor(&tmp_object);
goto exit;
} else if (Z_STRVAL_P(member)[0] == '\0' && Z_STRLEN_P(member) != 0) {
zval_ptr_dtor(&tmp_object);
zend_throw_error(NULL, "Cannot access property started with '\\0'");
retval = &EG(uninitialized_zval);
goto exit;
}
}
zval_ptr_dtor(&tmp_object);
if ((type != BP_VAR_IS)) {
zend_error(E_NOTICE,"Undefined property: %s::$%s", ZSTR_VAL(zobj->ce->name), Z_STRVAL_P(member));
}
retval = &EG(uninitialized_zval);
exit:
if (UNEXPECTED(Z_REFCOUNTED(tmp_member))) {
zval_ptr_dtor(&tmp_member);
}
return retval;
}
zend_get_property_offset
//獲取偏移量
static zend_always_inline uint32_t zend_get_property_offset(zend_class_entry *ce, zend_string *member, int silent, void **cache_slot) /* {{{ */
{
zval *zv;
zend_property_info *property_info = NULL;
uint32_t flags;
zend_class_entry *scope;
if (cache_slot && EXPECTED(ce == CACHED_PTR_EX(cache_slot))) {
return (uint32_t)(intptr_t)CACHED_PTR_EX(cache_slot + 1);
}
if (UNEXPECTED(ZSTR_VAL(member)[0] == '\0' && ZSTR_LEN(member) != 0)) {
if (!silent) {
zend_throw_error(NULL, "Cannot access property started with '\\0'");
}
return ZEND_WRONG_PROPERTY_OFFSET;
}
//普通屬性不存在
if (UNEXPECTED(zend_hash_num_elements(&ce->properties_info) == 0)) {
goto exit_dynamic; //動態的
}
//
zv = zend_hash_find(&ce->properties_info, member); // 共有屬性到這一步
if (EXPECTED(zv != NULL)) {
property_info = (zend_property_info*)Z_PTR_P(zv); //獲取到屬性資訊
flags = property_info->flags; //獲取屬性的標識 public protected private
//判斷是否是私有屬性
if (UNEXPECTED((flags & ZEND_ACC_SHADOW) != 0)) {
/* if it's a shadow - go to access it's private */
//父類的私有屬性
property_info = NULL;
} else {
if (EXPECTED(zend_verify_property_access(property_info, ce) != 0)) {
if (UNEXPECTED(!(flags & ZEND_ACC_CHANGED))
|| UNEXPECTED((flags & ZEND_ACC_PRIVATE))) {
if (UNEXPECTED((flags & ZEND_ACC_STATIC) != 0)) {
if (!silent) {
//靜態屬性的讀取方式不正確
zend_error(E_NOTICE, "Accessing static property %s::$%s as non static", ZSTR_VAL(ce->name), ZSTR_VAL(member));
}
return ZEND_DYNAMIC_PROPERTY_OFFSET;
}
//公共屬性到這一步了
goto exit;
}
} else {
/* Try to look in the scope instead */
property_info = ZEND_WRONG_PROPERTY_INFO;
}
}
}
if (EG(fake_scope)) {
scope = EG(fake_scope);
} else {
scope = zend_get_executed_scope();
}
if (scope != ce
&& scope
&& is_derived_class(ce, scope)
&& (zv = zend_hash_find(&scope->properties_info, member)) != NULL
&& ((zend_property_info*)Z_PTR_P(zv))->flags & ZEND_ACC_PRIVATE) {
property_info = (zend_property_info*)Z_PTR_P(zv);
if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) != 0)) {
return ZEND_DYNAMIC_PROPERTY_OFFSET;
}
} else if (UNEXPECTED(property_info == NULL)) {
exit_dynamic:
if (cache_slot) {
CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(intptr_t)ZEND_DYNAMIC_PROPERTY_OFFSET);
}
return ZEND_DYNAMIC_PROPERTY_OFFSET;
} else if (UNEXPECTED(property_info == ZEND_WRONG_PROPERTY_INFO)) {
/* Information was available, but we were denied access. Error out. */
if (!silent) {
zend_throw_error(NULL, "Cannot access %s property %s::$%s", zend_visibility_string(flags), ZSTR_VAL(ce->name), ZSTR_VAL(member));
}
return ZEND_WRONG_PROPERTY_OFFSET;
}
exit:
if (cache_slot) {
CACHE_POLYMORPHIC_PTR_EX(cache_slot, ce, (void*)(intptr_t)property_info->offset);
}
return property_info->offset;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結