diff --git a/Zend/tests/property_hooks/abstract_get_only_readonly.phpt b/Zend/tests/property_hooks/abstract_get_only_readonly.phpt new file mode 100644 index 000000000000..b911e8f7d861 --- /dev/null +++ b/Zend/tests/property_hooks/abstract_get_only_readonly.phpt @@ -0,0 +1,18 @@ +--TEST-- +Readonly property satisfies get-only abstract property +--FILE-- +prop = $prop; + } +} +$c = new C(42); +var_dump($c->prop); +?> +--EXPECT-- +int(42) diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly.phpt index e8cb95019cc0..d82579379e16 100644 --- a/Zend/tests/property_hooks/abstract_get_set_readonly.phpt +++ b/Zend/tests/property_hooks/abstract_get_set_readonly.phpt @@ -1,13 +1,16 @@ --TEST-- -readonly property does not satisfy get/set abstract property +Readonly property cannot implement set hook of get/set abstract property --FILE-- prop = $prop; + } } ?> --EXPECTF-- -Fatal error: Class C contains 1 abstract method and must therefore be declared abstract or implement the remaining method (P::$prop::set) in %s on line %d +Fatal error: Readonly property C::$prop cannot implement set hook required by class A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly_promoted.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly_promoted.phpt new file mode 100644 index 000000000000..ff4070e9413d --- /dev/null +++ b/Zend/tests/property_hooks/abstract_get_set_readonly_promoted.phpt @@ -0,0 +1,13 @@ +--TEST-- +Readonly promoted property cannot implement set hook of get/set abstract property +--FILE-- + +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by class A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly_public.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly_public.phpt new file mode 100644 index 000000000000..e9b976ff787a --- /dev/null +++ b/Zend/tests/property_hooks/abstract_get_set_readonly_public.phpt @@ -0,0 +1,16 @@ +--TEST-- +Readonly property cannot implement set hook of public get/set abstract property +--FILE-- +prop = $prop; + } +} +?> +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by class A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly_public_promoted.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly_public_promoted.phpt new file mode 100644 index 000000000000..3754f4b4afa7 --- /dev/null +++ b/Zend/tests/property_hooks/abstract_get_set_readonly_public_promoted.phpt @@ -0,0 +1,13 @@ +--TEST-- +Readonly promoted property cannot implement set hook of public get/set abstract property +--FILE-- + +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by class A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly_public_set.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly_public_set.phpt new file mode 100644 index 000000000000..9b200c4869b4 --- /dev/null +++ b/Zend/tests/property_hooks/abstract_get_set_readonly_public_set.phpt @@ -0,0 +1,16 @@ +--TEST-- +Readonly public(set) property cannot implement set hook of public get/set abstract property +--FILE-- +prop = $prop; + } +} +?> +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by class A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/abstract_get_set_readonly_public_set_promoted.phpt b/Zend/tests/property_hooks/abstract_get_set_readonly_public_set_promoted.phpt new file mode 100644 index 000000000000..26d9f6891634 --- /dev/null +++ b/Zend/tests/property_hooks/abstract_get_set_readonly_public_set_promoted.phpt @@ -0,0 +1,13 @@ +--TEST-- +Readonly promoted public(set) property cannot implement set hook of public get/set abstract property +--FILE-- + +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by class A::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/interface_get_set_readonly.phpt b/Zend/tests/property_hooks/interface_get_set_readonly.phpt deleted file mode 100644 index 692a0bc7e787..000000000000 --- a/Zend/tests/property_hooks/interface_get_set_readonly.phpt +++ /dev/null @@ -1,15 +0,0 @@ ---TEST-- -readonly property does not satisfy get/set interface property ---DESCRIPTION-- -The error message should be improved, the set access level comes from readonly. ---FILE-- - ---EXPECTF-- -Fatal error: Set access level of C::$prop must be omitted (as in class I) in %s on line %d diff --git a/Zend/tests/property_hooks/interface_get_only_readonly.phpt b/Zend/tests/property_hooks/interface_readonly_get_only.phpt similarity index 79% rename from Zend/tests/property_hooks/interface_get_only_readonly.phpt rename to Zend/tests/property_hooks/interface_readonly_get_only.phpt index 38ac375a4957..8004048bd80d 100644 --- a/Zend/tests/property_hooks/interface_get_only_readonly.phpt +++ b/Zend/tests/property_hooks/interface_readonly_get_only.phpt @@ -1,5 +1,5 @@ --TEST-- -readonly property satisfies get only interface property +Readonly property satisfies get-only interface property --FILE-- prop = $prop; + } +} +?> +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by interface I::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/interface_readonly_get_set_promoted.phpt b/Zend/tests/property_hooks/interface_readonly_get_set_promoted.phpt new file mode 100644 index 000000000000..023036fefda9 --- /dev/null +++ b/Zend/tests/property_hooks/interface_readonly_get_set_promoted.phpt @@ -0,0 +1,13 @@ +--TEST-- +Readonly promoted property cannot implement set hook of get/set interface property +--FILE-- + +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by interface I::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/interface_readonly_get_set_public_set.phpt b/Zend/tests/property_hooks/interface_readonly_get_set_public_set.phpt new file mode 100644 index 000000000000..3005e4976b76 --- /dev/null +++ b/Zend/tests/property_hooks/interface_readonly_get_set_public_set.phpt @@ -0,0 +1,16 @@ +--TEST-- +Readonly public(set) property cannot implement set hook of get/set interface property +--FILE-- +prop = $prop; + } +} +?> +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by interface I::$prop in %s on line %d diff --git a/Zend/tests/property_hooks/interface_readonly_get_set_public_set_promoted.phpt b/Zend/tests/property_hooks/interface_readonly_get_set_public_set_promoted.phpt new file mode 100644 index 000000000000..5f047290ac80 --- /dev/null +++ b/Zend/tests/property_hooks/interface_readonly_get_set_public_set_promoted.phpt @@ -0,0 +1,13 @@ +--TEST-- +Readonly promoted public(set) property cannot implement set hook of get/set interface property +--FILE-- + +--EXPECTF-- +Fatal error: Readonly property C::$prop cannot implement set hook required by interface I::$prop in %s on line %d diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index d70d08f5f1c4..5fe9a731091b 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1475,6 +1475,20 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke ZSTR_VAL(ce->name), ZSTR_VAL(key)); } } + if (parent_info->hooks + && parent_info->hooks[ZEND_PROPERTY_HOOK_SET] + && parent_info->hooks[ZEND_PROPERTY_HOOK_SET]->common.fn_flags & ZEND_ACC_ABSTRACT + && child_info->flags & ZEND_ACC_READONLY + && !property_has_operation(child_info, ZEND_PROPERTY_HOOK_SET)) { + zend_error_noreturn( + E_COMPILE_ERROR, + "Readonly property %s::$%s cannot implement set hook required by %s %s::$%s", + ZSTR_VAL(ce->name), + ZSTR_VAL(key), + zend_get_object_type_case(parent_info->ce, false), + ZSTR_VAL(parent_info->ce->name), + ZSTR_VAL(key)); + } if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_SET_MASK)) /* Get-only virtual properties have no set visibility, so any child visibility is fine. */ && !(parent_info->hooks && (parent_info->flags & ZEND_ACC_VIRTUAL) && !parent_info->hooks[ZEND_PROPERTY_HOOK_SET])) {