mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Ignore inheritance rules on private methods
Closes GH-5401
This commit is contained in:
parent
371e29ef3a
commit
272b887b7b
9 changed files with 123 additions and 6 deletions
|
@ -194,6 +194,9 @@ PHP 8.0 UPGRADE NOTES
|
||||||
RFC: https://wiki.php.net/rfc/locale_independent_float_to_string
|
RFC: https://wiki.php.net/rfc/locale_independent_float_to_string
|
||||||
. Removed support for deprecated curly braces for offset access
|
. Removed support for deprecated curly braces for offset access
|
||||||
RFC: https://wiki.php.net/rfc/deprecate_curly_braces_array_access
|
RFC: https://wiki.php.net/rfc/deprecate_curly_braces_array_access
|
||||||
|
. Applying the final modifier on a private method will now produce a warning
|
||||||
|
unless that method is the constructor.
|
||||||
|
RFC: https://wiki.php.net/rfc/inheritance_private_methods
|
||||||
|
|
||||||
- COM:
|
- COM:
|
||||||
. Removed the ability to import case-insensitive constants from type
|
. Removed the ability to import case-insensitive constants from type
|
||||||
|
@ -584,6 +587,10 @@ PHP 8.0 UPGRADE NOTES
|
||||||
RFC: https://wiki.php.net/rfc/constructor_promotion
|
RFC: https://wiki.php.net/rfc/constructor_promotion
|
||||||
. Added support for `match` expression.
|
. Added support for `match` expression.
|
||||||
RFC: https://wiki.php.net/rfc/match_expression_v2
|
RFC: https://wiki.php.net/rfc/match_expression_v2
|
||||||
|
. Private methods declared on a parent class no longer enforce any
|
||||||
|
inheritance rules on the methods of a child class. (with the exception of
|
||||||
|
final private constructors)
|
||||||
|
RFC: https://wiki.php.net/rfc/inheritance_private_methods
|
||||||
|
|
||||||
- Date:
|
- Date:
|
||||||
. Added DateTime::createFromInterface() and
|
. Added DateTime::createFromInterface() and
|
||||||
|
|
|
@ -24,7 +24,7 @@ class C extends B {
|
||||||
(new C)->test();
|
(new C)->test();
|
||||||
|
|
||||||
class D {
|
class D {
|
||||||
private final function method(&$x) {
|
private function method(&$x) {
|
||||||
++$x;
|
++$x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6486,6 +6486,10 @@ zend_string *zend_begin_method_decl(zend_op_array *op_array, zend_string *name,
|
||||||
|
|
||||||
zend_string *lcname;
|
zend_string *lcname;
|
||||||
|
|
||||||
|
if ((fn_flags & ZEND_ACC_PRIVATE) && (fn_flags & ZEND_ACC_FINAL) && !zend_is_constructor(name)) {
|
||||||
|
zend_error(E_COMPILE_WARNING, "Private methods cannot be final as they are never overridden by other classes");
|
||||||
|
}
|
||||||
|
|
||||||
if (in_interface) {
|
if (in_interface) {
|
||||||
if (!(fn_flags & ZEND_ACC_PUBLIC) || (fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_ABSTRACT))) {
|
if (!(fn_flags & ZEND_ACC_PUBLIC) || (fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_ABSTRACT))) {
|
||||||
zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface method "
|
zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface method "
|
||||||
|
|
|
@ -828,6 +828,14 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
|
||||||
uint32_t parent_flags = parent->common.fn_flags;
|
uint32_t parent_flags = parent->common.fn_flags;
|
||||||
zend_function *proto;
|
zend_function *proto;
|
||||||
|
|
||||||
|
if (UNEXPECTED((parent_flags & ZEND_ACC_PRIVATE) && !(parent_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_CTOR))) {
|
||||||
|
if (!check_only) {
|
||||||
|
child->common.fn_flags |= ZEND_ACC_CHANGED;
|
||||||
|
}
|
||||||
|
/* The parent method is private and not an abstract so we don't need to check any inheritance rules */
|
||||||
|
return INHERITANCE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
if (!checked && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
|
if (!checked && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
|
||||||
if (check_only) {
|
if (check_only) {
|
||||||
return INHERITANCE_ERROR;
|
return INHERITANCE_ERROR;
|
||||||
|
@ -869,10 +877,6 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
|
||||||
child->common.fn_flags |= ZEND_ACC_CHANGED;
|
child->common.fn_flags |= ZEND_ACC_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((parent_flags & ZEND_ACC_PRIVATE) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
|
|
||||||
return INHERITANCE_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
proto = parent->common.prototype ?
|
proto = parent->common.prototype ?
|
||||||
parent->common.prototype : parent;
|
parent->common.prototype : parent;
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ abstract class base {
|
||||||
public $a = 'base';
|
public $a = 'base';
|
||||||
|
|
||||||
// disallow cloning once forever
|
// disallow cloning once forever
|
||||||
final private function __clone() {}
|
final protected function __clone() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class test extends base {
|
class test extends base {
|
||||||
|
|
21
tests/classes/final_private_ctor.phpt
Normal file
21
tests/classes/final_private_ctor.phpt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
Final private constructors cannot be overridden
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Base
|
||||||
|
{
|
||||||
|
private final function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Extended extends Base
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Cannot override final method Base::__construct() in %s on line %d
|
51
tests/classes/inheritance_007.phpt
Normal file
51
tests/classes/inheritance_007.phpt
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
--TEST--
|
||||||
|
Ensure private methods with the same name are not checked for inheritance rules - final
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class A {
|
||||||
|
function callYourPrivates() {
|
||||||
|
$this->normalPrivate();
|
||||||
|
$this->finalPrivate();
|
||||||
|
}
|
||||||
|
function notOverridden_callYourPrivates() {
|
||||||
|
$this->normalPrivate();
|
||||||
|
$this->finalPrivate();
|
||||||
|
}
|
||||||
|
private function normalPrivate() {
|
||||||
|
echo __METHOD__ . PHP_EOL;
|
||||||
|
}
|
||||||
|
final private function finalPrivate() {
|
||||||
|
echo __METHOD__ . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class B extends A {
|
||||||
|
function callYourPrivates() {
|
||||||
|
$this->normalPrivate();
|
||||||
|
$this->finalPrivate();
|
||||||
|
}
|
||||||
|
private function normalPrivate() {
|
||||||
|
echo __METHOD__ . PHP_EOL;
|
||||||
|
}
|
||||||
|
final private function finalPrivate() {
|
||||||
|
echo __METHOD__ . PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$a = new A();
|
||||||
|
$a->callYourPrivates();
|
||||||
|
$a->notOverridden_callYourPrivates();
|
||||||
|
$b = new B();
|
||||||
|
$b->callYourPrivates();
|
||||||
|
$b->notOverridden_callYourPrivates();
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: Private methods cannot be final as they are never overridden by other classes %s
|
||||||
|
|
||||||
|
Warning: Private methods cannot be final as they are never overridden by other classes %s
|
||||||
|
A::normalPrivate
|
||||||
|
A::finalPrivate
|
||||||
|
A::normalPrivate
|
||||||
|
A::finalPrivate
|
||||||
|
B::normalPrivate
|
||||||
|
B::finalPrivate
|
||||||
|
A::normalPrivate
|
||||||
|
A::finalPrivate
|
16
tests/classes/inheritance_008.phpt
Normal file
16
tests/classes/inheritance_008.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
Ensure private methods with the same name are not checked for inheritance rules - static
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class A {
|
||||||
|
static private function foo() { }
|
||||||
|
private function bar() {}
|
||||||
|
}
|
||||||
|
class B extends A {
|
||||||
|
private function foo() {}
|
||||||
|
static private function bar() {}
|
||||||
|
}
|
||||||
|
echo 'OK';
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
OK
|
14
tests/classes/inheritance_009.phpt
Normal file
14
tests/classes/inheritance_009.phpt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
Ensure private methods with the same name are not checked for inheritance rules - abstract
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class A {
|
||||||
|
private function test() {}
|
||||||
|
}
|
||||||
|
abstract class B extends A {
|
||||||
|
abstract function test();
|
||||||
|
}
|
||||||
|
echo 'OK';
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
OK
|
Loading…
Add table
Add a link
Reference in a new issue