diff --git a/Zend/tests/accessors/accessor_isset_unset_auto_implement_basic.phpt b/Zend/tests/accessors/accessor_isset_unset_auto_implement_basic.phpt index cd9b9e96e90b0..31157c9f12cce 100644 --- a/Zend/tests/accessors/accessor_isset_unset_auto_implement_basic.phpt +++ b/Zend/tests/accessors/accessor_isset_unset_auto_implement_basic.phpt @@ -31,6 +31,7 @@ $o->b: 3600 Getting $b is_null($o->b): 0 Getting $b +Getting $b isset($o->b): 1 Unsetting $o->b Setting $b diff --git a/Zend/tests/accessors/accessor_isset_unset_default_implemented_basic.phpt b/Zend/tests/accessors/accessor_isset_unset_default_implemented_basic.phpt index 5d03552772497..eed78968e2caa 100644 --- a/Zend/tests/accessors/accessor_isset_unset_default_implemented_basic.phpt +++ b/Zend/tests/accessors/accessor_isset_unset_default_implemented_basic.phpt @@ -29,6 +29,7 @@ $o->b: 3600 Getting $b is_null($o->b): 0 Getting $b +Getting $b isset($o->b): 1 Unsetting $o->b Setting $b diff --git a/Zend/tests/accessors/accessor_object_get_autoimplement_basic.phpt b/Zend/tests/accessors/accessor_object_get_autoimplement_basic.phpt index c924fd3e9f238..a66ecfdfa89e0 100644 --- a/Zend/tests/accessors/accessor_object_get_autoimplement_basic.phpt +++ b/Zend/tests/accessors/accessor_object_get_autoimplement_basic.phpt @@ -1,5 +1,5 @@ --TEST-- -ZE2 Tests that an auto-implemented getter has a protected auto-implemented variable defined and that it can be retrieved through the accessor +ZE2 Tests that an auto-implemented getter has an auto-implemented variable defined and that it can be retrieved through the accessor --FILE-- __b = 5; - } } $o = new AccessorTest(); -$rf = new ReflectionClass($o); -foreach($rf->getProperties(ReflectionProperty::IS_PROTECTED) as $rfp) { - if($rfp->getName() == '__b') - echo "Protected property: \$".$rfp->getName()." exists.\n"; -} +var_dump($o); echo "\$o->b: ".$o->b."\n"; echo "Done\n"; ?> --EXPECTF-- -Protected property: $__b exists. -$o->b: 5 -Done +object(AccessorTest)#1 (1) { + ["b"]=> + NULL +} +$o->b: +Done \ No newline at end of file diff --git a/Zend/tests/accessors/accessor_object_get_undefined_error.phpt b/Zend/tests/accessors/accessor_object_get_undefined_error.phpt index dc8ce1c883011..c596bbcbb2361 100644 --- a/Zend/tests/accessors/accessor_object_get_undefined_error.phpt +++ b/Zend/tests/accessors/accessor_object_get_undefined_error.phpt @@ -15,4 +15,6 @@ echo "\$o->b: ".$o->b."\n"; echo "Done\n"; ?> --EXPECTF-- -Fatal error: Cannot get property AccessorTest::$b, no getter defined. in %s on line %d \ No newline at end of file +Warning: Cannot get property AccessorTest::$b, no getter defined in %s on line %d +$o->b: +Done diff --git a/Zend/tests/accessors/accessor_object_set_autoimplement_basic.phpt b/Zend/tests/accessors/accessor_object_set_autoimplement_basic.phpt index f5972e1119090..acb3ed17203f6 100644 --- a/Zend/tests/accessors/accessor_object_set_autoimplement_basic.phpt +++ b/Zend/tests/accessors/accessor_object_set_autoimplement_basic.phpt @@ -1,5 +1,5 @@ --TEST-- -ZE2 Tests that an auto-implemented setter has a protected auto-implemented variable defined and that it can be changed through the accessor +ZE2 Tests that an auto-implemented setter has an auto-implemented variable defined and that it can be changed through the accessor --FILE-- __b = 5; + $this->b = 5; } - public function _getProtectedValue() { return $this->__b; } } $o = new AccessorTest(); -$rf = new ReflectionClass($o); -foreach($rf->getProperties(ReflectionProperty::IS_PROTECTED) as $rfp) { - if($rfp->getName() == '__b') - echo "Protected property: \$".$rfp->getName()." exists.\n"; -} - -echo "\$o->b: ".$o->_getProtectedValue()."\n"; +print_r($o); $o->b = 10; -echo "\$o->b: ".$o->_getProtectedValue()."\n"; +print_r($o); echo "Done\n"; ?> --EXPECTF-- -Protected property: $__b exists. -$o->b: 5 -$o->b: 10 +AccessorTest Object +( + [b] => 5 +) +AccessorTest Object +( + [b] => 10 +) Done diff --git a/Zend/tests/accessors/accessor_object_set_undefined_error.phpt b/Zend/tests/accessors/accessor_object_set_undefined_error.phpt index ffc98de1f27c6..2bdfc215e811a 100644 --- a/Zend/tests/accessors/accessor_object_set_undefined_error.phpt +++ b/Zend/tests/accessors/accessor_object_set_undefined_error.phpt @@ -13,4 +13,4 @@ $o = new AccessorTest(); $o->b = 10; ?> --EXPECTF-- -Fatal error: Cannot set property AccessorTest::$b, no setter defined. in %s on line %d \ No newline at end of file +Warning: Cannot set property AccessorTest::$b, no setter defined in %s on line %d \ No newline at end of file diff --git a/Zend/tests/accessors/accessor_object_set_undefined_unset_called_error.phpt b/Zend/tests/accessors/accessor_object_set_undefined_unset_called_error.phpt index d296d908e6459..3748f0516cb9f 100644 --- a/Zend/tests/accessors/accessor_object_set_undefined_unset_called_error.phpt +++ b/Zend/tests/accessors/accessor_object_set_undefined_unset_called_error.phpt @@ -14,4 +14,8 @@ $o = new AccessorTest(); unset($o->b); ?> --EXPECTF-- -Fatal error: Cannot set property AccessorTest::$b, no setter defined. in %s on line %d \ No newline at end of file +Fatal error: Cannot set property AccessorTest::$b, no setter defined. in %s on line %d + +This test needs to be re-worked / checked against v1.2 changes. Technically it is working as it should +(unset is not causing an error) but that "feature" has not yet been put in place. +Need to trace what's going on here. \ No newline at end of file diff --git a/Zend/tests/accessors/accessor_std_lazy_load_with_getter_basic.phpt b/Zend/tests/accessors/accessor_std_lazy_load_with_getter_basic.phpt index c3dfeb53fda35..c13e87413bda8 100644 --- a/Zend/tests/accessors/accessor_std_lazy_load_with_getter_basic.phpt +++ b/Zend/tests/accessors/accessor_std_lazy_load_with_getter_basic.phpt @@ -11,10 +11,11 @@ class TimePeriod { public $Hours { get { echo "Get Hours Called\n"; - return $this->Hours = 1; /* Calls Setter */ + return $this->Hours ?: $this->Hours = 2; /* Calls Setter */ } set { - $this->Hours = 1; /* Sets an anonymous property due to guard allowing lazy load */ + echo "Set Hours Called ({$value})\n"; + $this->Hours = $value; } } } @@ -24,8 +25,16 @@ $o = new TimePeriod(); echo $o->Hours."\n"; echo $o->Hours."\n"; $o->Hours = 4; +echo $o->Hours."\n"; +echo "Done\n"; ?> --EXPECTF-- Get Hours Called -1 -1 +Set Hours Called (2) +2 +Get Hours Called +2 +Set Hours Called (4) +Get Hours Called +4 +Done \ No newline at end of file diff --git a/Zend/tests/accessors/duplicate_property_declared_error.phpt b/Zend/tests/accessors/duplicate_property_declared_error.phpt new file mode 100644 index 0000000000000..a67a52d8dc168 --- /dev/null +++ b/Zend/tests/accessors/duplicate_property_declared_error.phpt @@ -0,0 +1,14 @@ +--TEST-- +ZE2 Tests that an accessor cannot be declared if a property is already declared +--FILE-- + +--EXPECTF-- +Fatal error: Cannot redeclare TimePeriod::$Seconds in %s on line %d \ No newline at end of file diff --git a/Zend/zend.h b/Zend/zend.h index 95abfd823b09c..4b9147a6e7baa 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -480,7 +480,6 @@ struct _zend_class_entry { HashTable function_table; HashTable properties_info; - HashTable accessors; zval **default_properties_table; zval **default_static_members_table; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index f62d9d2b5e03c..6761c7f46cd19 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3402,6 +3402,7 @@ ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, in property_info.doc_comment_len = doc_comment_len; property_info.ce = ce; + property_info.ai = NULL; zend_hash_quick_update(&ce->properties_info, name, name_length+1, h, &property_info, sizeof(zend_property_info), NULL); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9a28a1c3cd4e3..1d9c5e7db8eca 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -108,20 +108,32 @@ ZEND_API zend_executor_globals executor_globals; static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */ { + zend_accessor_info *parent_ai = property_info->ai; + if (!IS_INTERNED(property_info->name)) { property_info->name = estrndup(property_info->name, property_info->name_length); } if (property_info->doc_comment) { property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len); } + if(parent_ai) { + property_info->ai = ecalloc(1, sizeof(zend_accessor_info)); + property_info->ai->flags = parent_ai->flags; + } } /* }}} */ static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */ { + zend_accessor_info *parent_ai = property_info->ai; + if (!IS_INTERNED(property_info->name)) { property_info->name = zend_strndup(property_info->name, property_info->name_length); } + if(parent_ai) { + property_info->ai = ecalloc(1, sizeof(zend_accessor_info)); + property_info->ai->flags = parent_ai->flags; + } } /* }}} */ @@ -131,6 +143,10 @@ static void zend_destroy_property_info(zend_property_info *property_info) /* {{{ if (property_info->doc_comment) { efree((char*)property_info->doc_comment); } + if(property_info->ai) { + efree(property_info->ai); + property_info->ai = NULL; + } } /* }}} */ @@ -730,14 +746,14 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* zend_do_fetch_class(&class_node, class_name TSRMLS_CC); } - if(result->op_type == IS_CV) { - /* Handle self::$Area accessors (normal and static) */ +/* if(result->op_type == IS_CV) { + Handle self::$Area accessors (normal and static) if(class_node.op_type == IS_VAR && class_node.EA == ZEND_FETCH_CLASS_SELF && CG(active_class_entry)) { const char *member_name = CG(active_op_array)->vars[result->u.op.var].name; zend_accessor_info **aipp; - /* If the member_name is an accessor */ + If the member_name is an accessor if(zend_hash_find((const HashTable *)&CG(active_class_entry)->accessors, member_name, strlen(member_name)+1, (void**)&aipp) == SUCCESS) { znode zn_self, zn_func, zn_arg_list; size_t member_name_len = strlen(member_name); @@ -750,20 +766,20 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* MAKE_ZNODEL(zn_func, fname, 5 + member_name_len); efree(fname); - /* We assume we will be used as a getter, if zend_do_assign() is called, it will backpatch as calling a setter */ + We assume we will be used as a getter, if zend_do_assign() is called, it will backpatch as calling a setter zend_do_begin_class_member_function_call(&zn_self, &zn_func TSRMLS_CC); zend_do_end_function_call(&zn_func, result, &zn_arg_list, 1, 0 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); return; } } - /* Handle parent::$Area accessors (normal and static) */ + Handle parent::$Area accessors (normal and static) if(class_node.op_type == IS_VAR && class_node.EA == ZEND_FETCH_CLASS_PARENT && CG(active_class_entry) && CG(active_class_entry)->parent) { const char *member_name = CG(active_op_array)->vars[result->u.op.var].name; zend_accessor_info **aipp; - /* If the member_name is an accessor */ + If the member_name is an accessor if(zend_hash_find((const HashTable *)&CG(active_class_entry)->parent->accessors, member_name, strlen(member_name)+1, (void**)&aipp) == SUCCESS) { znode zn_parent, zn_func, zn_arg_list; size_t member_name_len = strlen(member_name); @@ -776,14 +792,14 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* MAKE_ZNODEL(zn_func, fname, 5 + member_name_len); efree(fname); - /* We assume we will be used as a getter, if zend_do_assign() is called, it will backpatch as calling a setter */ + We assume we will be used as a getter, if zend_do_assign() is called, it will backpatch as calling a setter zend_do_begin_class_member_function_call(&zn_parent, &zn_func TSRMLS_CC); zend_do_end_function_call(&zn_func, result, &zn_arg_list, 1, 0 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); return; } } - /* Handle Shape::$Area static accessor */ + Handle Shape::$Area static accessor if(class_node.op_type == IS_CONST) { zend_class_entry **classpp; char *lcname = zend_str_tolower_dup(Z_STRVAL(class_node.u.constant), Z_STRLEN(class_node.u.constant)); @@ -811,7 +827,7 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* Z_STRVAL(zn_func.u.constant)[2] = 'g'; ZVAL_LONG(&zn_arg_list.u.constant, 0); - /* We assume we will be used as a getter, if zend_do_assign() is called, it will backpatch as calling a setter */ + We assume we will be used as a getter, if zend_do_assign() is called, it will backpatch as calling a setter zend_do_begin_class_member_function_call(&zn_class, &zn_func TSRMLS_CC); zend_do_end_function_call(&zn_func, result, &zn_arg_list, 1, 0 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); @@ -821,7 +837,7 @@ void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* } efree(lcname); } - } + }*/ zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); @@ -1654,110 +1670,114 @@ int zend_do_verify_access_types(const znode *current_access_type, const znode *n /* }}} */ void zend_declare_accessor(znode *var_name TSRMLS_DC) { /* {{{ */ - /* Generate Hash Value for Variable */ - ulong hash_value = zend_hash_func(Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1); - zend_accessor_info **aipp, *ai; - - /* Locate or create accessor_info structure */ - if(zend_hash_quick_find(&CG(active_class_entry)->accessors, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, hash_value, (void**) &aipp) != SUCCESS) { - ai = ecalloc(1, sizeof(zend_accessor_info)); - ai->flags = CG(access_type); - ai->doc_comment = CG(doc_comment); - ai->doc_comment_len = CG(doc_comment_len); - CG(doc_comment) = NULL; - CG(doc_comment_len) = 0; - zend_hash_quick_update(&CG(active_class_entry)->accessors, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, hash_value, (void**)&ai, sizeof(zend_accessor_info*), NULL); + zend_property_info *property_info; + char *vn_copy = NULL; + zend_uint orig_ce_flags = CG(active_class_entry)->ce_flags; + + // Hide that we're working with an interface during property accessor declaration + CG(active_class_entry)->ce_flags &= ~ZEND_ACC_INTERFACE; + + /* zend_do_declare_property free's the string, we still need it later on, so copy and put back in place */ + vn_copy = (char *) estrndup(Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)); + zend_do_declare_property(var_name, NULL, CG(access_type) & ~(ZEND_ACC_FINAL) TSRMLS_CC); + Z_STRVAL(var_name->u.constant) = vn_copy; + CG(active_class_entry)->ce_flags = orig_ce_flags; + + if(zend_hash_find(&CG(active_class_entry)->properties_info, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, (void **) &property_info)==SUCCESS) { + if(property_info->ai != NULL) { + zend_error_noreturn(E_COMPILE_ERROR, "property_info for %s::$%s already has accessor_info created, should not happen in zend_declare_accessor()", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); + } + + property_info->ai = ecalloc(1, sizeof(zend_accessor_info)); + property_info->ai->flags = CG(access_type); + } else { + zend_error_noreturn(E_COMPILE_ERROR, "Property_info for %s::$%s is not present, should not happen in zend_declare_accessor()", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); } } /* }}} */ void zend_do_begin_accessor_declaration(znode *function_token, znode *var_name, znode *modifiers, int return_reference, int has_params TSRMLS_DC) /* {{{ */ { - /* Generate Hash Value for Variable */ - ulong hash_value = zend_hash_func(Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1); - zend_accessor_info **aipp, *ai; + zend_property_info *property_info; zend_function *func = NULL; - /* Locate or create accessor_info structure */ - if(zend_hash_quick_find(&CG(active_class_entry)->accessors, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, hash_value, (void**) &aipp) == SUCCESS) { - ai = *aipp; - } else { - zend_error(E_COMPILE_ERROR, "Unable to locate accessor structure '%s', please report this to php-internals.", Z_STRVAL(var_name->u.constant)); - } + if(zend_hash_find(&CG(active_class_entry)->properties_info, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, (void **) &property_info)==SUCCESS) { + /* Inherit flags from outer accessor definition */ + Z_LVAL(modifiers->u.constant) |= (property_info->ai->flags & ZEND_ACC_STATIC); - /* Inherit flags from outer accessor definition */ - Z_LVAL(modifiers->u.constant) |= (ai->flags & ZEND_ACC_STATIC); + if(Z_TYPE(function_token->u.constant) == IS_STRING && strcasecmp("get", Z_STRVAL(function_token->u.constant)) == 0) { + /* Convert type and variable name to __getHours() */ + char *tmp = strcatalloc("__get", 5, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); + efree(Z_STRVAL(function_token->u.constant)); + ZVAL_STRINGL(&function_token->u.constant, tmp, 5 + Z_STRLEN(var_name->u.constant), 0); - if(Z_TYPE(function_token->u.constant) == IS_STRING && strcasecmp("get", Z_STRVAL(function_token->u.constant)) == 0) { - /* Convert type and variable name to __getHours() */ - char *tmp = strcatalloc("__get", 5, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); - efree(Z_STRVAL(function_token->u.constant)); - ZVAL_STRINGL(&function_token->u.constant, tmp, 5 + Z_STRLEN(var_name->u.constant), 0); + if(has_params) { + zend_error(E_COMPILE_ERROR, "Getters do not accept parameters for variable %s::$%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); + } - if(has_params) { - zend_error(E_COMPILE_ERROR, "Getters do not accept parameters for variable %s::$%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); - } + /* Declare Function */ + zend_do_begin_function_declaration(function_token, function_token, 1, return_reference, modifiers, ZEND_FNP_PROP_GETTER TSRMLS_CC); + } else if(Z_TYPE(function_token->u.constant) == IS_STRING && strcasecmp("set", Z_STRVAL(function_token->u.constant)) == 0) { + /* Convert type and variable name to __setHours() */ + char *tmp = strcatalloc("__set", 5, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); + znode unused_node, unused_node2, value_node; - /* Declare Function */ - zend_do_begin_function_declaration(function_token, function_token, 1, return_reference, modifiers, ZEND_FNP_PROP_GETTER TSRMLS_CC); - } else if(Z_TYPE(function_token->u.constant) == IS_STRING && strcasecmp("set", Z_STRVAL(function_token->u.constant)) == 0) { - /* Convert type and variable name to __setHours() */ - char *tmp = strcatalloc("__set", 5, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); - znode unused_node, unused_node2, value_node; + efree(Z_STRVAL(function_token->u.constant)); + ZVAL_STRINGL(&function_token->u.constant, tmp, 5 + Z_STRLEN(var_name->u.constant), 0); - efree(Z_STRVAL(function_token->u.constant)); - ZVAL_STRINGL(&function_token->u.constant, tmp, 5 + Z_STRLEN(var_name->u.constant), 0); + if(return_reference) { + zend_error(E_WARNING, "Property setter %s::$%s indicates a return reference with '&', setters do not return values, ignored.", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); + } + /* Declare Function */ + zend_do_begin_function_declaration(function_token, function_token, 1, ZEND_RETURN_VAL, modifiers, ZEND_FNP_PROP_SETTER TSRMLS_CC); - if(return_reference) { - zend_error(E_WARNING, "Property setter %s::$%s indicates a return reference with '&', setters do not return values, ignored.", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); - } - /* Declare Function */ - zend_do_begin_function_declaration(function_token, function_token, 1, ZEND_RETURN_VAL, modifiers, ZEND_FNP_PROP_SETTER TSRMLS_CC); + if(!has_params) { + /* Add $value parameter to __setHours() */ + unused_node.op_type = unused_node2.op_type = IS_UNUSED; + unused_node.u.op.num = unused_node2.u.op.num = 1; - if(!has_params) { - /* Add $value parameter to __setHours() */ - unused_node.op_type = unused_node2.op_type = IS_UNUSED; - unused_node.u.op.num = unused_node2.u.op.num = 1; + ZVAL_STRINGL(&value_node.u.constant, "value", 5, 1); - ZVAL_STRINGL(&value_node.u.constant, "value", 5, 1); + zend_do_receive_arg(ZEND_RECV, &value_node, &unused_node, NULL, &unused_node2, 0 TSRMLS_CC); + } + } else if(Z_TYPE(function_token->u.constant) == IS_LONG && Z_LVAL(function_token->u.constant) == T_ISSET) { + /* Convert type and variable name to __issetHours() */ + char *tmp = strcatalloc("__isset", 7, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); + ZVAL_STRINGL(&function_token->u.constant, tmp, 7 + Z_STRLEN(var_name->u.constant), 0); - zend_do_receive_arg(ZEND_RECV, &value_node, &unused_node, NULL, &unused_node2, 0 TSRMLS_CC); - } - } else if(Z_TYPE(function_token->u.constant) == IS_LONG && Z_LVAL(function_token->u.constant) == T_ISSET) { - /* Convert type and variable name to __issetHours() */ - char *tmp = strcatalloc("__isset", 7, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); - ZVAL_STRINGL(&function_token->u.constant, tmp, 7 + Z_STRLEN(var_name->u.constant), 0); + if(has_params) { + zend_error(E_COMPILE_ERROR, "Issetters do not accept parameters for variable %s::$%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); + } - if(has_params) { - zend_error(E_COMPILE_ERROR, "Issetters do not accept parameters for variable %s::$%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); - } + /* Declare Function */ + zend_do_begin_function_declaration(function_token, function_token, 1, ZEND_RETURN_VAL, modifiers, ZEND_FNP_PROP_ISSETTER TSRMLS_CC); + } else if(Z_TYPE(function_token->u.constant) == IS_LONG && Z_LVAL(function_token->u.constant) == T_UNSET) { + /* Convert type and variable name to __unsetHours() */ + char *tmp = strcatalloc("__unset", 7, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); + ZVAL_STRINGL(&function_token->u.constant, tmp, 7 + Z_STRLEN(var_name->u.constant), 0); - /* Declare Function */ - zend_do_begin_function_declaration(function_token, function_token, 1, ZEND_RETURN_VAL, modifiers, ZEND_FNP_PROP_ISSETTER TSRMLS_CC); - } else if(Z_TYPE(function_token->u.constant) == IS_LONG && Z_LVAL(function_token->u.constant) == T_UNSET) { - /* Convert type and variable name to __unsetHours() */ - char *tmp = strcatalloc("__unset", 7, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); - ZVAL_STRINGL(&function_token->u.constant, tmp, 7 + Z_STRLEN(var_name->u.constant), 0); + if(has_params) { + zend_error(E_COMPILE_ERROR, "Unsetters do not accept parameters for variable %s::$%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); + } - if(has_params) { - zend_error(E_COMPILE_ERROR, "Unsetters do not accept parameters for variable %s::$%s", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); + /* Declare Function */ + zend_do_begin_function_declaration(function_token, function_token, 1, ZEND_RETURN_VAL, modifiers, ZEND_FNP_PROP_UNSETTER TSRMLS_CC); + } else { + zend_error(E_COMPILE_ERROR, "Unknown accessor '%s', expecting get or set for variable $%s", Z_STRVAL(function_token->u.constant), Z_STRVAL(var_name->u.constant)); } + func = (zend_function*)CG(active_op_array); - /* Declare Function */ - zend_do_begin_function_declaration(function_token, function_token, 1, ZEND_RETURN_VAL, modifiers, ZEND_FNP_PROP_UNSETTER TSRMLS_CC); + if (func->common.purpose == ZEND_FNP_PROP_GETTER) { + property_info->ai->getter = func; + } else if(func->common.purpose == ZEND_FNP_PROP_SETTER) { + property_info->ai->setter = func; + } else if(func->common.purpose == ZEND_FNP_PROP_ISSETTER) { + property_info->ai->isset = func; + } else if(func->common.purpose == ZEND_FNP_PROP_UNSETTER) { + property_info->ai->unset = func; + } } else { - zend_error(E_COMPILE_ERROR, "Unknown accessor '%s', expecting get or set for variable $%s", Z_STRVAL(function_token->u.constant), Z_STRVAL(var_name->u.constant)); - } - func = (zend_function*)CG(active_op_array); - - if (func->common.purpose == ZEND_FNP_PROP_GETTER) { - ai->getter = func; - } else if(func->common.purpose == ZEND_FNP_PROP_SETTER) { - ai->setter = func; - } else if(func->common.purpose == ZEND_FNP_PROP_ISSETTER) { - ai->isset = func; - } else if(func->common.purpose == ZEND_FNP_PROP_UNSETTER) { - ai->unset = func; + zend_error_noreturn(E_COMPILE_ERROR, "Property_info for %s::$%s is not present, should not happen in zend_do_begin_accessor_declaration()", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); } } /* }}} */ @@ -1766,55 +1786,39 @@ void zend_do_end_accessor_declaration(znode *function_token, znode *var_name, zn { /* If we have no function body, create an automatic body */ if(body == NULL && (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) == 0) { - char *int_var_name = strcatalloc("__", 2, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant) TSRMLS_CC); - - zend_property_info **zpi; - zval eval_php_code; zend_uint original_compiler_options = CG(compiler_options); CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL; if(CG(active_op_array)->purpose == ZEND_FNP_PROP_GETTER) { - /* Equivalent to: return $this->__Property; or static equivalent */ + /* Equivalent to: return $this->Property; or static equivalent */ zend_uint bufsize = 16 + Z_STRLEN(var_name->u.constant) + 1 + 1; char *buffer = emalloc(bufsize); - if(zend_hash_find(&CG(active_class_entry)->properties_info, int_var_name, Z_STRLEN(var_name->u.constant)+3, (void**) &zpi) != SUCCESS) { - znode zn_prop; - MAKE_ZNODEL(zn_prop, int_var_name, 2 + Z_STRLEN(var_name->u.constant)); - zend_do_declare_property(&zn_prop, NULL, ZEND_ACC_PROTECTED | (Z_LVAL(modifiers->u.constant) & ZEND_ACC_STATIC) TSRMLS_CC); - } - Z_STRVAL(eval_php_code) = buffer; Z_TYPE(eval_php_code) = IS_STRING; if((Z_LVAL(modifiers->u.constant) & ZEND_ACC_STATIC)) { - Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "return self::$__%s;", Z_STRVAL(var_name->u.constant)); + Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "return self::$%s;", Z_STRVAL(var_name->u.constant)); } else { - Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "return $this->__%s;", Z_STRVAL(var_name->u.constant)); + Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "return $this->%s;", Z_STRVAL(var_name->u.constant)); } zend_compile_string_inline(&eval_php_code, (char*)CG(active_op_array)->filename TSRMLS_CC); efree(buffer); zend_do_extended_info(TSRMLS_C); } else if(CG(active_op_array)->purpose == ZEND_FNP_PROP_SETTER) { - /* Equivalent to: $this->__Property = $value; */ + /* Equivalent to: $this->Property = $value; */ zend_uint bufsize = 9 + Z_STRLEN(var_name->u.constant) + 10 + 1; char *buffer = emalloc(bufsize); - if(zend_hash_find(&CG(active_class_entry)->properties_info, int_var_name, Z_STRLEN(var_name->u.constant)+3, (void**) &zpi) != SUCCESS) { - znode zn_prop; - MAKE_ZNODEL(zn_prop, int_var_name, 2 + Z_STRLEN(var_name->u.constant)); - zend_do_declare_property(&zn_prop, NULL, ZEND_ACC_PROTECTED | (Z_LVAL(modifiers->u.constant) & ZEND_ACC_STATIC) TSRMLS_CC); - } - Z_STRVAL(eval_php_code) = buffer; Z_TYPE(eval_php_code) = IS_STRING; if((Z_LVAL(modifiers->u.constant) & ZEND_ACC_STATIC)) { - Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "self::$__%s = $value;", Z_STRVAL(var_name->u.constant)); + Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "self::$%s = $value;", Z_STRVAL(var_name->u.constant)); } else { - Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "$this->__%s = $value;", Z_STRVAL(var_name->u.constant)); + Z_STRLEN(eval_php_code) = snprintf(Z_STRVAL(eval_php_code), bufsize, "$this->%s = $value;", Z_STRVAL(var_name->u.constant)); } zend_compile_string_inline(&eval_php_code, (char*)CG(active_op_array)->filename TSRMLS_CC); efree(buffer); @@ -1852,10 +1856,9 @@ void zend_do_end_accessor_declaration(znode *function_token, znode *var_name, zn efree(buffer); zend_do_extended_info(TSRMLS_C); } - efree(int_var_name); CG(compiler_options) = original_compiler_options; } else if(body != NULL && (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) == ZEND_ACC_INTERFACE) { - zend_error(E_WARNING, "Interface %s::$%s %ster cannot have implementation defined, implementation ignored.", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant), zend_fn_purpose_string(CG(active_op_array))); + zend_error(E_WARNING, "Interface %s::$%s %ster cannot have implementation defined, implementation ignored.", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant), zend_fn_purpose_string((zend_function*)CG(active_op_array))); } zend_do_end_function_declaration(function_token TSRMLS_CC); @@ -1864,38 +1867,35 @@ void zend_do_end_accessor_declaration(znode *function_token, znode *var_name, zn void zend_finalize_accessor(znode *var_name TSRMLS_DC) { /* {{{ */ - /* Generate Hash Value for Variable */ - ulong hash_value = zend_hash_func(Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1); - zend_accessor_info **aipp, *ai; - - /* Locate or create accessor_info structure */ - if(zend_hash_quick_find(&CG(active_class_entry)->accessors, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, hash_value, (void**) &aipp) == SUCCESS) { - ai = *aipp; - if(!ai->isset && ai->getter) { + zend_property_info *property_info; + + if(zend_hash_find(&CG(active_class_entry)->properties_info, Z_STRVAL(var_name->u.constant), Z_STRLEN(var_name->u.constant)+1, (void **) &property_info)==SUCCESS) { + if(!property_info->ai->isset && property_info->ai->getter) { znode zn_fntoken, zn_modifiers; INIT_ZNODE(zn_fntoken); ZVAL_LONG(&zn_fntoken.u.constant, T_ISSET); /* Inherit flags accessor declaration */ INIT_ZNODE(zn_modifiers); - Z_LVAL(zn_modifiers.u.constant) = ai->flags; + Z_LVAL(zn_modifiers.u.constant) = property_info->ai->flags; zend_do_begin_accessor_declaration(&zn_fntoken, var_name, &zn_modifiers, 0, 0 TSRMLS_CC); zend_do_end_accessor_declaration(&zn_fntoken, var_name, &zn_modifiers, NULL TSRMLS_CC); } - if(!ai->unset && ai->setter) { + if(!property_info->ai->unset && property_info->ai->setter) { znode zn_fntoken, zn_modifiers; INIT_ZNODE(zn_fntoken); ZVAL_LONG(&zn_fntoken.u.constant, T_UNSET); /* Inherit flags accessor declaration */ INIT_ZNODE(zn_modifiers); - Z_LVAL(zn_modifiers.u.constant) = ai->flags; + Z_LVAL(zn_modifiers.u.constant) = property_info->ai->flags; zend_do_begin_accessor_declaration(&zn_fntoken, var_name, &zn_modifiers, 0, 0 TSRMLS_CC); zend_do_end_accessor_declaration(&zn_fntoken, var_name, &zn_modifiers, NULL TSRMLS_CC); } - + } else { + zend_error_noreturn(E_COMPILE_ERROR, "Property_info for %s::$%s is not present, should not happen in zend_finalize_accessor()", CG(active_class_entry)->name, Z_STRVAL(var_name->u.constant)); } } /* }}} */ @@ -3970,33 +3970,22 @@ static inline void zend_do_update_accessors(zend_class_entry *ce TSRMLS_DC) /* { zend_hash_get_current_data(&ce->function_table, (void *) &func) == SUCCESS; zend_hash_move_forward(&ce->function_table)) { if (IS_ACCESSOR_FN(func)) { - const char *varname = ZEND_ACC_NAME(func); - ulong hash_value = zend_hash_func(varname, strlen(varname)+1); - - zend_accessor_info **aipp, *ai; - - if(zend_hash_quick_find(&ce->accessors, varname, strlen(varname)+1, hash_value, (void**) &aipp) != SUCCESS) { - zend_accessor_info **parent_aipp = NULL; - - ai = emalloc(sizeof(zend_accessor_info)); - memset(ai, 0, sizeof(zend_accessor_info)); - zend_hash_quick_update(&ce->accessors, varname, strlen(varname)+1, hash_value, (void**)&ai, sizeof(zend_accessor_info*), NULL); - - if(ce && ce->parent && zend_hash_quick_find(&ce->parent->accessors, varname, strlen(varname)+1, hash_value, (void**) &parent_aipp) == SUCCESS) { - ai->flags = (*parent_aipp)->flags; + zend_property_info *property_info; + const char *var_name = ZEND_ACC_NAME(func); + zend_uint var_name_len = strlen(var_name); + + if(zend_hash_find(&ce->properties_info, var_name, var_name_len+1, (void **) &property_info)==SUCCESS) { + if(func->common.purpose == ZEND_FNP_PROP_GETTER) { + property_info->ai->getter = func; + } else if(func->common.purpose == ZEND_FNP_PROP_SETTER) { + property_info->ai->setter = func; + } else if(func->common.purpose == ZEND_FNP_PROP_ISSETTER) { + property_info->ai->isset = func; + } else if(func->common.purpose == ZEND_FNP_PROP_UNSETTER) { + property_info->ai->unset = func; } } else { - ai = *aipp; - } - - if(func->common.purpose == ZEND_FNP_PROP_GETTER) { - ai->getter = func; - } else if(func->common.purpose == ZEND_FNP_PROP_SETTER) { - ai->setter = func; - } else if(func->common.purpose == ZEND_FNP_PROP_ISSETTER) { - ai->isset = func; - } else if(func->common.purpose == ZEND_FNP_PROP_UNSETTER) { - ai->unset = func; + zend_error_noreturn(E_COMPILE_ERROR, "Property_info for %s::$%s is not present, should not happen in zend_do_update_accessors()", ce->name, var_name); } } } @@ -4681,7 +4670,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* { for (zend_hash_internal_pointer_reset(&ce->traits[i]->properties_info); zend_hash_get_current_data(&ce->traits[i]->properties_info, (void *) &property_info) == SUCCESS; zend_hash_move_forward(&ce->traits[i]->properties_info)) { - /* first get the unmangeld name if necessary, + /* first get the unmangled name if necessary, * then check whether the property is already there */ flags = property_info->flags; @@ -4753,6 +4742,13 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* { zend_declare_property_ex(ce, prop_name, prop_name_length, prop_value, flags, doc_comment, property_info->doc_comment_len TSRMLS_CC); + if(property_info->ai) { + zend_property_info *created_property_info; + if(zend_hash_find(&ce->properties_info, prop_name, prop_name_length+1, (void**) &created_property_info) == SUCCESS) { + created_property_info->ai = ecalloc(1, sizeof(zend_accessor_info)); + created_property_info->ai->flags = property_info->ai->flags; + } + } } } } @@ -7299,7 +7295,6 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes, 0); zend_hash_init_ex(&ce->constants_table, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0); - zend_hash_init_ex(&ce->accessors, 0, NULL, ZEND_ACCESSOR_DTOR, persistent_hashes, 0); if (ce->type == ZEND_INTERNAL_CLASS) { #ifdef ZTS @@ -7678,9 +7673,8 @@ zend_accessor_info *zend_get_accessor_info_from_function(const zend_function *fu { const char *member_name = NULL; zend_uint member_name_len = 0; - ulong hash_value = 0; - zend_accessor_info **aipp; + zend_property_info *property_info; if(!func || !IS_ACCESSOR_FN(func)) return NULL; @@ -7697,10 +7691,8 @@ zend_accessor_info *zend_get_accessor_info_from_function(const zend_function *fu } member_name_len = strlen(member_name); - hash_value = zend_inline_hash_func(member_name, member_name_len+1); - - if(zend_hash_quick_find(&func->common.scope->accessors, member_name, member_name_len+1, hash_value, (void**)&aipp) == SUCCESS) { - return *aipp; + if(zend_hash_find(&func->common.scope->properties_info, member_name, member_name_len+1, (void**)&property_info) == SUCCESS) { + return property_info->ai; } return NULL; } @@ -7767,16 +7759,14 @@ zend_accessor_info *zend_get_accessor_from_init_static_method_call(zend_op_array } } if(classpp) { - zend_accessor_info **aipp; + zend_property_info *property_info; char *lcname2 = zend_str_tolower_dup(Z_STRVAL_P(op2zv)+5, Z_STRLEN_P(op2zv)-5); /* strlen("__get") == 5 */ - if(zend_hash_find(&(*classpp)->accessors, lcname2, Z_STRLEN_P(op2zv)-4, (void**)&aipp) == SUCCESS) { - efree(lcname2); - - return *aipp; - } else { + if(zend_hash_find(&(*classpp)->properties_info, lcname2, Z_STRLEN_P(op2zv)-4, (void**)&property_info) == SUCCESS) { efree(lcname2); + return property_info->ai; } + efree(lcname2); } } return NULL; diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 9e6e12cdf4d52..d5ba5ac783bb1 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -255,6 +255,7 @@ typedef struct _zend_property_info { const char *doc_comment; int doc_comment_len; zend_class_entry *ce; + struct _zend_accessor_info *ai; } zend_property_info; @@ -389,8 +390,6 @@ typedef union _zend_function { typedef struct _zend_accessor_info { zend_uint flags; - const char *doc_comment; - int doc_comment_len; zend_function *getter; zend_function *setter; zend_function *isset; @@ -726,7 +725,6 @@ ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC); ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC); ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC); -ZEND_API void zend_accessor_dtor(zend_accessor_info **ai); ZEND_API void zend_function_dtor(zend_function *function); ZEND_API void destroy_zend_class(zend_class_entry **pce); void zend_class_add_ref(zend_class_entry **ce); @@ -734,7 +732,6 @@ void zend_class_add_ref(zend_class_entry **ce); ZEND_API void zend_mangle_property_name(char **dest, int *dest_length, const char *src1, int src1_length, const char *src2, int src2_length, int internal); ZEND_API int zend_unmangle_property_name(const char *mangled_property, int mangled_property_len, const char **class_name, const char **prop_name); -#define ZEND_ACCESSOR_DTOR (void (*)(void *)) zend_accessor_dtor #define ZEND_FUNCTION_DTOR (void (*)(void *)) zend_function_dtor #define ZEND_CLASS_DTOR (void (*)(void *)) destroy_zend_class diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 7fa6d519f752a..168042739578a 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -132,7 +132,7 @@ ZEND_API HashTable *zend_std_get_debug_info(zval *object, int *is_temp TSRMLS_DC } /* }}} */ -static zval *zend_std_call_getter(zval *object, zval *member, zend_function *func TSRMLS_DC) /* {{{ */ +static zval *zend_std_call_getter(zval *object, zval *member TSRMLS_DC) /* {{{ */ { zval *retval = NULL; zend_class_entry *ce = Z_OBJCE_P(object); @@ -140,16 +140,12 @@ static zval *zend_std_call_getter(zval *object, zval *member, zend_function *fun /* __get handler is called with one argument: property name - it should return whether the call was successfull or not + it should return whether the call was successful or not */ SEPARATE_ARG_IF_REF(member); - if (func->common.num_args == 1) { - zend_call_method_with_1_params(&object, ce, &func, func->common.function_name, &retval, member); - } else { - zend_call_method_with_0_params(&object, ce, &func, func->common.function_name, &retval); - } + zend_call_method_with_1_params(&object, ce, &ce->__get, ZEND_GET_FUNC_NAME, &retval, member); zval_ptr_dtor(&member); @@ -161,7 +157,7 @@ static zval *zend_std_call_getter(zval *object, zval *member, zend_function *fun } /* }}} */ -static int zend_std_call_setter(zval *object, zval *member, zval *value, zend_function *func TSRMLS_DC) /* {{{ */ +static int zend_std_call_setter(zval *object, zval *member, zval *value TSRMLS_DC) /* {{{ */ { zval *retval = NULL; int result; @@ -174,13 +170,9 @@ static int zend_std_call_setter(zval *object, zval *member, zval *value, zend_fu property name value to be set - it should return whether the call was successfull or not + it should return whether the call was successful or not */ - if (func->common.num_args == 2) { - zend_call_method_with_2_params(&object, ce, &func, func->common.function_name, &retval, member, value); - } else { - zend_call_method_with_1_params(&object, ce, &func, func->common.function_name, &retval, value); - } + zend_call_method_with_2_params(&object, ce, &ce->__set, ZEND_SET_FUNC_NAME, &retval, member, value); zval_ptr_dtor(&member); zval_ptr_dtor(&value); @@ -265,7 +257,7 @@ static zend_always_inline zend_bool is_derived_class(zend_class_entry *child_cla } /* }}} */ -static zend_always_inline struct _zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zval *member, int silent, const zend_literal *key TSRMLS_DC) /* {{{ */ +zend_always_inline struct _zend_property_info *zend_get_property_info_quick(zend_class_entry *ce, zval *member, int silent, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_property_info *property_info; zend_property_info *scope_property_info; @@ -406,55 +398,14 @@ static int zend_get_property_guard(zend_object *zobj, zend_property_info *proper } /* }}} */ -zend_function inline *zend_locate_getter(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ -{ - zend_object *zobj = Z_OBJ_P(object); - zend_accessor_info **ai = NULL; - ulong hash_value = key ? key->hash_value : member && member->type == IS_STRING ? zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1) : 0; - - if(zend_hash_quick_find(&zobj->ce->accessors, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, hash_value, (void**) &ai) == SUCCESS) { - if((*ai)->getter) { - /* If public getter, no access check required */ - if((*ai)->getter->common.fn_flags & ZEND_ACC_PUBLIC) { - return (*ai)->getter; - } - return zend_std_get_method(&object, (char *)(*ai)->getter->common.function_name, strlen((*ai)->getter->common.function_name), NULL TSRMLS_CC); - } - zend_error_noreturn(E_ERROR, "Cannot get property %s::$%s, no getter defined.", zobj->ce->name, Z_STRVAL_P(member)); - } - return zobj->ce->__get; -} -/* }}} */ - -zend_function inline *zend_locate_setter(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */ -{ - zend_object *zobj = Z_OBJ_P(object); - zend_accessor_info **ai = NULL; - ulong hash_value = key ? key->hash_value : member && member->type == IS_STRING ? zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1) : 0; - - if(zend_hash_quick_find(&zobj->ce->accessors, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, hash_value, (void**) &ai) == SUCCESS) { - if((*ai)->setter) { - /* If public setter, no access check required */ - if((*ai)->setter->common.fn_flags & ZEND_ACC_PUBLIC) { - return (*ai)->setter; - } - return zend_std_get_method(&object, (char *)(*ai)->setter->common.function_name, strlen((*ai)->setter->common.function_name), NULL TSRMLS_CC); - } - zend_error_noreturn(E_ERROR, "Cannot set property %s::$%s, no setter defined.", zobj->ce->name, Z_STRVAL_P(member)); - } - return zobj->ce->__set; -} -/* }}} */ - zval *zend_std_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj; zval *tmp_member = NULL; - zval **retval; + zval **retval = NULL; zval *rv = NULL; zend_property_info *property_info; int silent; - zend_function *getter = NULL; silent = (type == BP_VAR_IS); zobj = Z_OBJ_P(object); @@ -469,14 +420,38 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li key = NULL; } - getter = zend_locate_getter(object, member, key TSRMLS_CC); - #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 */ - property_info = zend_get_property_info_quick(zobj->ce, member, (getter != NULL), key TSRMLS_CC); + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC); + + /* Getter shadows property unless in guard */ + if(property_info && property_info->ai) { + zend_guard *guard = NULL; + + if(!property_info->ai->getter) { + zend_error(E_WARNING, "Cannot get property %s::$%s, no getter defined", zobj->ce->name, Z_STRVAL_P(member)); + return EG(uninitialized_zval_ptr); + } + + if(zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && guard->in_get == 0) { + /* If public getter, no access check required */ + zend_function *getter = property_info->ai->getter->common.fn_flags & ZEND_ACC_PUBLIC + ? property_info->ai->getter + : zend_std_get_method(&object, (char *)property_info->ai->getter->common.function_name, strlen(property_info->ai->getter->common.function_name), NULL TSRMLS_CC); + if(getter) { + guard->in_get = 1; + zend_call_method_with_0_params(&object, zobj->ce, &getter, getter->common.function_name, &rv); + guard->in_get = 0; + if(rv) { + Z_DELREF_P(rv); + } + return rv; + } + } + } if (UNEXPECTED(!property_info) || ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && @@ -486,10 +461,9 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li (*(retval = &zobj->properties_table[property_info->offset]) == NULL)) : (UNEXPECTED(!zobj->properties) || UNEXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &retval) == FAILURE)))) { - zend_guard *guard = NULL; - if ( getter != NULL && zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && !guard->in_get) { + if ( zobj->ce->__get != NULL && zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && !guard->in_get) { /* have getter - try with it! */ Z_ADDREF_P(object); @@ -497,7 +471,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li SEPARATE_ZVAL(&object); } guard->in_get = 1; /* prevent circular getting */ - rv = zend_std_call_getter(object, member, getter TSRMLS_CC); + rv = zend_std_call_getter(object, member TSRMLS_CC); guard->in_get = 0; if (rv) { @@ -526,7 +500,7 @@ zval *zend_std_read_property(zval *object, zval *member, int type, const zend_li Z_DELREF_P(object); } } else { - if (getter && guard && guard->in_get == 1) { + if (zobj->ce->__get && guard && guard->in_get == 1) { if (Z_STRVAL_P(member)[0] == '\0') { if (Z_STRLEN_P(member) == 0) { zend_error(E_ERROR, "Cannot access empty property"); @@ -556,7 +530,6 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, c zval *tmp_member = NULL; zval **variable_ptr; zend_property_info *property_info; - zend_function *setter = NULL; zobj = Z_OBJ_P(object); @@ -570,9 +543,34 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, c key = NULL; } - setter = zend_locate_setter(object, member, key TSRMLS_CC); + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__set != NULL), key TSRMLS_CC); - property_info = zend_get_property_info_quick(zobj->ce, member, (setter != NULL), key TSRMLS_CC); + /* Setter shadows property unless in guard */ + if(property_info && property_info->ai) { + zend_guard *guard = NULL; + + if(!property_info->ai->setter) { + zend_error(E_WARNING, "Cannot set property %s::$%s, no setter defined", zobj->ce->name, Z_STRVAL_P(member)); + return; + } + if(zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && guard->in_set == 0) { + /* If public setter, no access check required */ + zend_function *setter = property_info->ai->setter->common.fn_flags & ZEND_ACC_PUBLIC + ? property_info->ai->setter + : zend_std_get_method(&object, (char *)property_info->ai->setter->common.function_name, strlen(property_info->ai->setter->common.function_name), NULL TSRMLS_CC); + if(setter) { + zval *retval = NULL; + + guard->in_set = 1; + zend_call_method_with_1_params(&object, zobj->ce, &setter, setter->common.function_name, &retval, value); + guard->in_set = 0; + if(retval) { + zval_ptr_dtor(&retval); + } + return; + } + } + } if (EXPECTED(property_info != NULL) && ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && @@ -613,15 +611,13 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, c } else { zend_guard *guard = NULL; - zend_get_property_guard(zobj, property_info, member, &guard); - - if (setter && guard && !guard->in_set) { + if (zobj->ce->__set && zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && !guard->in_set) { Z_ADDREF_P(object); if (PZVAL_IS_REF(object)) { SEPARATE_ZVAL(&object); } guard->in_set = 1; /* prevent circular setting */ - if (zend_std_call_setter(object, member, value, setter TSRMLS_CC) != SUCCESS) { + if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) { /* for now, just ignore it - setter should take care of warnings, etc. */ } guard->in_set = 0; @@ -647,7 +643,7 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, c } zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), NULL); } - } else if (setter && guard && guard->in_set == 1) { + } else if (zobj->ce->__set && guard && guard->in_set == 1) { if (Z_STRVAL_P(member)[0] == '\0') { if (Z_STRLEN_P(member) == 0) { zend_error(E_ERROR, "Cannot access empty property"); @@ -753,7 +749,6 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const ze zval tmp_member; zval **retval; zend_property_info *property_info; - zend_function *getter = NULL; zobj = Z_OBJ_P(object); @@ -769,8 +764,28 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const ze fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); #endif - getter = zend_locate_getter(object, member, key TSRMLS_CC); - property_info = zend_get_property_info_quick(zobj->ce, member, (getter != NULL), key TSRMLS_CC); + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__get != NULL), key TSRMLS_CC); + + /* Getter shadows property unless in guard */ + if(property_info && property_info->ai) { + zend_guard *guard = NULL; + + if(!property_info->ai->getter) { + zend_error(E_WARNING, "Cannot get property %s::$%s, no getter defined", zobj->ce->name, Z_STRVAL_P(member)); + return &EG(uninitialized_zval_ptr); + } + + if(zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && guard->in_get == 0) { + /* If public getter, no access check required */ + zend_function *getter = property_info->ai->getter->common.fn_flags & ZEND_ACC_PUBLIC + ? property_info->ai->getter + : zend_std_get_method(&object, (char *)property_info->ai->getter->common.function_name, strlen(property_info->ai->getter->common.function_name), NULL TSRMLS_CC); + if(getter) { + /* we do have getter - fail and let it try again with usual get/set */ + return NULL; + } + } + } if (UNEXPECTED(!property_info) || ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && @@ -783,7 +798,7 @@ static zval **zend_std_get_property_ptr_ptr(zval *object, zval *member, const ze zval *new_zval; zend_guard *guard; - if (!getter || + if (!zobj->ce->__get || zend_get_property_guard(zobj, property_info, member, &guard) != SUCCESS || (property_info && guard->in_get)) { /* we don't have access controls - will just add it */ @@ -826,10 +841,6 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter zend_object *zobj = Z_OBJ_P(object); zval *tmp_member = NULL; zend_property_info *property_info; - zend_function *unsetter = NULL; - - zend_accessor_info **ai = NULL; - ulong hash_value; if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) { ALLOC_ZVAL(tmp_member); @@ -841,21 +852,35 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter key = NULL; } - hash_value = key ? key->hash_value : zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1); + property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__unset != NULL), key TSRMLS_CC); - if(zend_hash_quick_find(&zobj->ce->accessors, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, hash_value, (void**) &ai) == SUCCESS) { - if((*ai)->unset) { + /* Unsetter shadows property unless in guard */ + if(property_info && property_info->ai) { + zend_guard *guard = NULL; + + if(!property_info->ai->unset) { + /* Have property but no unsetter, just return and do not throw error */ + return; + } + + if(zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && guard->in_unset == 0) { /* If public unsetter, no access check required */ - if((*ai)->unset->common.fn_flags & ZEND_ACC_PUBLIC) { - unsetter = (*ai)->unset; - } else { - unsetter = zend_std_get_method(&object, (char *)(*ai)->unset->common.function_name, strlen((*ai)->unset->common.function_name), NULL TSRMLS_CC); + zend_function *unsetter = property_info->ai->unset->common.fn_flags & ZEND_ACC_PUBLIC + ? property_info->ai->unset + : zend_std_get_method(&object, (char *)property_info->ai->unset->common.function_name, strlen(property_info->ai->unset->common.function_name), NULL TSRMLS_CC); + if(unsetter) { + zval *retval = NULL; + guard->in_unset = 1; + zend_call_method_with_0_params(&object, zobj->ce, &unsetter, unsetter->common.function_name, &retval); + guard->in_unset = 0; + if(retval) { + zval_ptr_dtor(&retval); + } + return; } } } - property_info = zend_get_property_info_quick(zobj->ce, member, (ai != NULL || zobj->ce->__unset != NULL), key TSRMLS_CC); - if (EXPECTED(property_info != NULL) && EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && !zobj->properties && @@ -868,31 +893,14 @@ static void zend_std_unset_property(zval *object, zval *member, const zend_liter UNEXPECTED(zend_hash_quick_del(zobj->properties, property_info->name, property_info->name_length+1, property_info->h) == FAILURE)) { zend_guard *guard = NULL; - if ((ai != NULL || zobj->ce->__unset) && - zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && - !guard->in_unset) { + if (zobj->ce->__unset && zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && !guard->in_unset) { /* have unsetter - try with it! */ Z_ADDREF_P(object); if (PZVAL_IS_REF(object)) { SEPARATE_ZVAL(&object); } guard->in_unset = 1; /* prevent circular unsetting */ - if(ai != NULL) { - if(unsetter != NULL) { - zend_call_method_with_0_params(&object, zobj->ce, &unsetter, unsetter->common.function_name, NULL); - } else { - /* Default implementation, equivalent to: $this->Property = NULL */ - zval *zv_null; - ALLOC_ZVAL(zv_null); - INIT_PZVAL(zv_null); - Z_TYPE_P(zv_null) = IS_NULL; - Z_LVAL_P(zv_null) = 0; - zend_std_write_property(object, member, zv_null, key TSRMLS_CC); - zval_ptr_dtor(&zv_null); - } - } else if(zobj->ce->__unset) { - zend_std_call_unsetter(object, member TSRMLS_CC); - } + zend_std_call_unsetter(object, member TSRMLS_CC); guard->in_unset = 0; zval_ptr_dtor(&object); } else if (zobj->ce->__unset && guard && guard->in_unset == 1) { @@ -1460,15 +1468,11 @@ static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */ { zend_object *zobj = Z_OBJ_P(object); - int result; + int result = 0; zval **value = NULL; zval *tmp_member = NULL; zend_property_info *property_info; - zend_function *issetter = NULL; - zend_accessor_info **ai = NULL; - ulong hash_value; - if (UNEXPECTED(Z_TYPE_P(member) != IS_STRING)) { ALLOC_ZVAL(tmp_member); *tmp_member = *member; @@ -1479,18 +1483,6 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, key = NULL; } - hash_value = key ? key->hash_value : zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1); - - if(zend_hash_quick_find(&zobj->ce->accessors, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, hash_value, (void**) &ai) == SUCCESS) { - if((*ai)->isset) { - /* If public issetter, no access check required */ - if((*ai)->isset->common.fn_flags & ZEND_ACC_PUBLIC) { - issetter = (*ai)->isset; - } else { - issetter = zend_std_get_method(&object, (char *)(*ai)->isset->common.function_name, strlen((*ai)->isset->common.function_name), NULL TSRMLS_CC); - } - } - } #if DEBUG_OBJECT_HANDLERS fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member)); @@ -1498,6 +1490,50 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, property_info = zend_get_property_info_quick(zobj->ce, member, 1, key TSRMLS_CC); + /* Issetter shadows property unless in guard */ + if(property_info && property_info->ai) { + zend_guard *guard = NULL; + + if(!property_info->ai->isset) { + /* Have property but no issetter, just return and do not throw error */ + return 0; + } + + if(zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && guard->in_isset == 0) { + /* If public issetter, no access check required */ + zend_function *issetter = property_info->ai->isset->common.fn_flags & ZEND_ACC_PUBLIC + ? property_info->ai->isset + : zend_std_get_method(&object, (char *)property_info->ai->isset->common.function_name, strlen(property_info->ai->isset->common.function_name), NULL TSRMLS_CC); + if(issetter) { + zval *retval = NULL; + guard->in_isset = 1; + zend_call_method_with_0_params(&object, zobj->ce, &issetter, issetter->common.function_name, &retval); + guard->in_isset = 0; + /* param has_set_exists: + * 0 (has) whether property exists and is not NULL + * 1 (set) whether property exists and is true + * 2 (exists) whether property exists + */ + if(retval) { + result = zend_is_true(retval); + zval_ptr_dtor(&retval); + } + if(result == 0 || has_set_exists == 2) + return result; + zval *rv; + rv = zend_std_read_property(object, member, BP_VAR_R, key TSRMLS_CC); + if (rv) { + Z_ADDREF_P(rv); + result = i_zend_is_true(rv); + zval_ptr_dtor(&rv); + } else { + result = 0; + } + return result; + } + } + } + if (UNEXPECTED(!property_info) || ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) ? @@ -1510,7 +1546,7 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, result = 0; if ((has_set_exists != 2) && - (ai != NULL || zobj->ce->__isset) && + zobj->ce->__isset && zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS && !guard->in_isset) { zval *rv; @@ -1521,44 +1557,16 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists, SEPARATE_ZVAL(&object); } guard->in_isset = 1; /* prevent circular getting */ - if(ai != NULL) { - if(issetter) { - zend_call_method_with_0_params(&object, zobj->ce, &issetter, issetter->common.function_name, &rv); - } else { - /* Default Implementation: $this->Property != NULL */ - - zval *value = zend_std_read_property(object, member, BP_VAR_R, key TSRMLS_CC); - - ALLOC_ZVAL(rv); - INIT_PZVAL(rv); - Z_TYPE_P(rv) = IS_BOOL; - if(Z_TYPE_P(value) == IS_NULL) { - Z_LVAL_P(rv) = 0; - } else { - Z_LVAL_P(rv) = 1; - } - } - } else { - rv = zend_std_call_issetter(object, member TSRMLS_CC); - } + rv = zend_std_call_issetter(object, member TSRMLS_CC); if (rv) { result = zend_is_true(rv); zval_ptr_dtor(&rv); if (has_set_exists && result) { - - zend_function *getter = zend_locate_getter(object, member, key TSRMLS_CC); - - if (EXPECTED(!EG(exception)) && getter && !guard->in_get) { - guard->in_get = 1; - rv = zend_std_call_getter(object, member, getter TSRMLS_CC); - guard->in_get = 0; - if (rv) { - Z_ADDREF_P(rv); - result = i_zend_is_true(rv); - zval_ptr_dtor(&rv); - } else { - result = 0; - } + rv = zend_std_read_property(object, member, BP_VAR_R, key TSRMLS_CC); + if (rv) { + Z_ADDREF_P(rv); + result = i_zend_is_true(rv); + zval_ptr_dtor(&rv); } else { result = 0; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index e4be4314427d9..1b59a5cc03053 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -129,14 +129,6 @@ ZEND_API void zend_function_dtor(zend_function *function) destroy_zend_function(function TSRMLS_CC); } -ZEND_API void zend_accessor_dtor(zend_accessor_info **ai) -{ - if((*ai)->doc_comment) { - efree((void*)(*ai)->doc_comment); - } - efree(*ai); -} - static void zend_cleanup_op_array_data(zend_op_array *op_array) { if (op_array->static_variables) { @@ -304,7 +296,6 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce) efree(ce->default_static_members_table); } zend_hash_destroy(&ce->properties_info); - zend_hash_destroy(&ce->accessors); str_efree(ce->name); zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->constants_table); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 541dec24d1792..5d17c4da433f9 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -188,12 +188,6 @@ typedef struct _property_reference { zend_property_info prop; } property_reference; -/* Struct for properties */ -typedef struct _property_accessor_reference { - zend_class_entry *ce; - zend_accessor_info ai; -} property_accessor_reference; - /* Struct for parameters */ typedef struct _parameter_reference { zend_uint offset; @@ -1419,22 +1413,15 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info /* }}} */ /* {{{ reflection_property_accessor_factory */ -static void reflection_property_accessor_factory(zend_class_entry *ce, zend_accessor_info *ai, zval *object TSRMLS_DC) +static void reflection_property_accessor_factory(zend_class_entry *ce, zend_property_info *property_info, zval *object TSRMLS_DC) { reflection_object *intern; zval *name; zval *classname; - property_accessor_reference *reference; - const char *prop_name = NULL; - - zend_function *func; + property_reference *reference; + const char *class_name, *prop_name; - if(ai->getter) { - func = ai->getter; - } else { - func = ai->setter; - } - prop_name = ZEND_ACC_NAME(func); + zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name); MAKE_STD_ZVAL(name); MAKE_STD_ZVAL(classname); @@ -1443,9 +1430,9 @@ static void reflection_property_accessor_factory(zend_class_entry *ce, zend_acce reflection_instantiate(reflection_property_accessor_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); - reference = (property_accessor_reference*) emalloc(sizeof(property_accessor_reference)); + reference = (property_reference*) emalloc(sizeof(property_reference)); reference->ce = ce; - reference->ai = *ai; + reference->prop = *property_info; intern->ptr = reference; intern->ref_type = REF_TYPE_PROPERTY_ACCESSOR; intern->ce = ce; @@ -4014,7 +4001,10 @@ static int _addproperty(zend_property_info *pptr TSRMLS_DC, int num_args, va_lis if (pptr->flags & filter) { ALLOC_ZVAL(property); - reflection_property_factory(ce, pptr, property TSRMLS_CC); + if(pptr->ai != NULL) + reflection_property_accessor_factory(ce, pptr, property TSRMLS_CC); + else + reflection_property_factory(ce, pptr, property TSRMLS_CC); add_next_index_zval(retval, property); } return 0; @@ -4050,52 +4040,6 @@ static int _adddynproperty(zval **pptr TSRMLS_DC, int num_args, va_list args, ze } /* }}} */ -/* {{{ _addaccessors */ -static int _addaccessors(zend_accessor_info **pptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) -{ - - /* If there is not already a property for the given name */ - - zend_class_entry *ce = *va_arg(args, zend_class_entry**); - zval *retval = va_arg(args, zval*); - zend_accessor_info *ai = *pptr; - zend_function *func = NULL; - - if(ai->getter) { - func = ai->getter; - } else { - func = ai->setter; - } - - if(func) { - HashPosition pos; - const char *name = ZEND_ACC_NAME(func); - zval member; - zval **entry, *result; - zval *property; - - ZVAL_STRINGL(&member, "name", 4, 0); - - /* Search existing values to ensure we don't already have a property defined by name */ - zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(retval), &pos); - while (zend_hash_get_current_data_ex(Z_ARRVAL_P(retval), (void **)&entry, &pos) == SUCCESS) { - result = zend_std_read_property(*entry, &member, 0, (const zend_literal *)NULL TSRMLS_CC ); - if(result != NULL && result->type == IS_STRING && strncmp(Z_STRVAL_P(result), name, strlen(name)) == 0) - return 0; /* Already have property named name defined */ - - zend_hash_move_forward_ex(Z_ARRVAL_P(retval), &pos); - } - - MAKE_STD_ZVAL(property); - reflection_property_accessor_factory(ce, ai, property TSRMLS_CC); - - add_next_index_zval(retval, property); - } - - return 0; -} -/* }}} */ - /* {{{ proto public ReflectionProperty[] ReflectionClass::getProperties([long $filter]) Returns an array of this class' properties */ ZEND_METHOD(reflection_class, getProperties) @@ -4124,8 +4068,6 @@ ZEND_METHOD(reflection_class, getProperties) HashTable *properties = Z_OBJ_HT_P(intern->obj)->get_properties(intern->obj TSRMLS_CC); zend_hash_apply_with_arguments(properties TSRMLS_CC, (apply_func_args_t) _adddynproperty, 2, &ce, return_value); } - - zend_hash_apply_with_arguments(&ce->accessors TSRMLS_CC, (apply_func_args_t) _addaccessors, 2, &ce, return_value); } /* }}} */ @@ -5303,9 +5245,8 @@ ZEND_METHOD(reflection_property_accessor, __construct) reflection_object *intern; zend_class_entry **pce; zend_class_entry *ce; - zend_accessor_info *ai = NULL, **aipp; - property_accessor_reference *reference; - zend_function *func = NULL; + zend_property_info *property_info = NULL; + property_reference *reference; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) { return; @@ -5337,30 +5278,26 @@ ZEND_METHOD(reflection_property_accessor, __construct) /* returns out of this function */ } - if (zend_hash_find(&ce->accessors, name_str, name_len + 1, (void **) &aipp) == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Accessor %s::$%s does not exist", ce->name, name_str); - return; - } - ai = *aipp; - - MAKE_STD_ZVAL(classname); - MAKE_STD_ZVAL(propname); - - func = ai->getter ? ai->getter : ai->setter; + if(zend_hash_find(&ce->properties_info, name_str, name_len+1, (void **) &property_info)==SUCCESS && property_info->ai != NULL) { + MAKE_STD_ZVAL(classname); + MAKE_STD_ZVAL(propname); - ZVAL_STRINGL(classname, func->common.scope->name, func->common.scope->name_length, 1); - ZVAL_STRING(propname, ZEND_ACC_NAME(func), 1); + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + ZVAL_STRINGL(propname, property_info->name, property_info->name_length, 1); - reflection_update_property(object, "class", classname); - reflection_update_property(object, "name", propname); + reflection_update_property(object, "class", classname); + reflection_update_property(object, "name", propname); - reference = (property_accessor_reference*) emalloc(sizeof(property_accessor_reference)); - reference->ai = *ai; - reference->ce = ce; - intern->ptr = reference; - intern->ref_type = REF_TYPE_PROPERTY_ACCESSOR; - intern->ce = ce; - intern->ignore_visibility = 0; + reference = (property_reference*) emalloc(sizeof(property_reference)); + reference->prop = *property_info; + reference->ce = ce; + intern->ptr = reference; + intern->ref_type = REF_TYPE_PROPERTY_ACCESSOR; + intern->ce = ce; + intern->ignore_visibility = 0; + } else { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Accessor %s::$%s does not exist", ce->name, name_str); + } } /* }}} */ @@ -5369,13 +5306,13 @@ ZEND_METHOD(reflection_property_accessor, __construct) ZEND_METHOD(reflection_property_accessor, getGetter) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; METHOD_NOTSTATIC(reflection_property_accessor_ptr); GET_REFLECTION_OBJECT_PTR(ref); - if(ref->ai.getter) { - reflection_method_factory(ref->ce, ref->ai.getter, NULL, return_value TSRMLS_CC); + if(ref->prop.ai->getter) { + reflection_method_factory(ref->ce, ref->prop.ai->getter, NULL, return_value TSRMLS_CC); return; } RETURN_FALSE @@ -5387,13 +5324,13 @@ ZEND_METHOD(reflection_property_accessor, getGetter) ZEND_METHOD(reflection_property_accessor, getSetter) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; METHOD_NOTSTATIC(reflection_property_accessor_ptr); GET_REFLECTION_OBJECT_PTR(ref); - if(ref->ai.setter) { - reflection_method_factory(ref->ce, ref->ai.setter, NULL, return_value TSRMLS_CC); + if(ref->prop.ai->setter) { + reflection_method_factory(ref->ce, ref->prop.ai->setter, NULL, return_value TSRMLS_CC); return; } RETURN_FALSE @@ -5403,13 +5340,13 @@ ZEND_METHOD(reflection_property_accessor, getSetter) static void _property_accessor_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */ { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; if (zend_parse_parameters_none() == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ref); - RETURN_BOOL(ref->ai.flags & mask); + RETURN_BOOL(ref->prop.ai->flags & mask); } /* }}} */ @@ -5458,14 +5395,14 @@ ZEND_METHOD(reflection_property_accessor, isDefault) ZEND_METHOD(reflection_property_accessor, getModifiers) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; if (zend_parse_parameters_none() == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ref); - RETURN_LONG(ref->ai.flags); + RETURN_LONG(ref->prop.ai->flags); } /* }}} */ @@ -5474,17 +5411,17 @@ ZEND_METHOD(reflection_property_accessor, getModifiers) ZEND_METHOD(reflection_property_accessor, getDeclaringClass) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; if (zend_parse_parameters_none() == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ref); - if(ref->ai.getter) { - zend_reflection_class_factory(ref->ai.getter->common.scope, return_value TSRMLS_CC); - } else if(ref->ai.setter) { - zend_reflection_class_factory(ref->ai.setter->common.scope, return_value TSRMLS_CC); + if(ref->prop.ai->getter) { + zend_reflection_class_factory(ref->prop.ai->getter->common.scope, return_value TSRMLS_CC); + } else if(ref->prop.ai->setter) { + zend_reflection_class_factory(ref->prop.ai->setter->common.scope, return_value TSRMLS_CC); } else { RETURN_FALSE; } @@ -5497,15 +5434,15 @@ ZEND_METHOD(reflection_property_accessor, getDeclaringClass) ZEND_METHOD(reflection_property_accessor, getDocComment) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; if (zend_parse_parameters_none() == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ref); - if(ref->ai.doc_comment) { - RETURN_STRINGL(ref->ai.doc_comment, ref->ai.doc_comment_len, 1); + if(ref->prop.doc_comment) { + RETURN_STRINGL(ref->prop.doc_comment, ref->prop.doc_comment_len, 1); } RETURN_FALSE; } @@ -5537,21 +5474,21 @@ ZEND_METHOD(reflection_property_accessor, setAccessible) ZEND_METHOD(reflection_property_accessor, getValue) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; zval *object, name; zval *retval = NULL; METHOD_NOTSTATIC(reflection_property_accessor_ptr); GET_REFLECTION_OBJECT_PTR(ref); - if(!ref->ai.getter) { + if(!ref->prop.ai->getter) { _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "No getter defined for property accessor %s::%s", intern->ce->name, Z_STRVAL(name)); zval_dtor(&name); return; } - if (!(ref->ai.getter->common.fn_flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) { + if (!(ref->prop.ai->getter->common.fn_flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) { _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot access non-public getter %s::%s", intern->ce->name, Z_STRVAL(name)); @@ -5563,7 +5500,7 @@ ZEND_METHOD(reflection_property_accessor, getValue) return; } - zend_call_method_with_0_params(&object, ref->ai.getter->common.scope, &ref->ai.getter, ref->ai.getter->common.function_name, &retval); + zend_call_method_with_0_params(&object, ref->prop.ai->getter->common.scope, &ref->prop.ai->getter, ref->prop.ai->getter->common.function_name, &retval); MAKE_COPY_ZVAL(&retval, return_value); if (retval != EG(uninitialized_zval_ptr)) { zval_ptr_dtor(&retval); @@ -5576,7 +5513,7 @@ ZEND_METHOD(reflection_property_accessor, getValue) ZEND_METHOD(reflection_property_accessor, setValue) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; zval *object, name; zval *value; zval *retval = NULL; @@ -5584,7 +5521,7 @@ ZEND_METHOD(reflection_property_accessor, setValue) METHOD_NOTSTATIC(reflection_property_accessor_ptr); GET_REFLECTION_OBJECT_PTR(ref); - if(!ref->ai.setter) { + if(!ref->prop.ai->setter) { _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "No setter defined for property accessor %s::%s", intern->ce->name, Z_STRVAL(name)); zval_dtor(&name); @@ -5595,7 +5532,7 @@ ZEND_METHOD(reflection_property_accessor, setValue) return; } - zend_call_method_with_1_params(&object, ref->ai.setter->common.scope, &ref->ai.setter, ref->ai.setter->common.function_name, &retval, value); + zend_call_method_with_1_params(&object, ref->prop.ai->setter->common.scope, &ref->prop.ai->setter, ref->prop.ai->setter->common.function_name, &retval, value); if (retval) { zval_ptr_dtor(&retval); @@ -5618,7 +5555,7 @@ ZEND_METHOD(reflection_property_accessor, getName) ZEND_METHOD(reflection_property_accessor, __toString) { reflection_object *intern; - property_accessor_reference *ref; + property_reference *ref; string str; if (zend_parse_parameters_none() == FAILURE) { @@ -5626,7 +5563,7 @@ ZEND_METHOD(reflection_property_accessor, __toString) } GET_REFLECTION_OBJECT_PTR(ref); string_init(&str); - _property_accessor_string(&str, &ref->ai, "" TSRMLS_CC); + _property_accessor_string(&str, ref->prop.ai, "" TSRMLS_CC); RETURN_STRINGL(str.string, str.len - 1, 0); } /* }}} */