PHP 8.0: Inheritance rules are not applied to private
class methods
PHP class methods declared private
are not accessible by child classes, but child classes can declare a method with the same name without having to adhere to Liskov Substitution Principle. PHP 8.0 strictly enforces method signatures, but private
class methods are not affected by this change.
Typed Properties introduced in PHP 7.4 already follow the same changes, and is not changed in PHP 8.0.
Prior to PHP 8.0, it was not allowed change to change the final
or static
flags of a class method. This is changed in PHP 8.0, that ensures private
methods can be truly private without adhering to the inheritance rules enforced from parent class(es).
In all PHP versions,
private
class method parameters,private
method return types, andprivate
class property types are not validated against Liskov Substitution Principle. These changes in PHP 8.0 only applies to changes inabstract
,static
, andfinal
flags in class methods.
final private
methods
Declaring a class method final private
does not make sense because all private
class methods are inaccessible by child classes anyway.
Prior to PHP 8.0, it was allowed to declare a class method as final private
, but it was not allowed to redeclare the method due to final
clause enforcement.
class Foo {
final private function testFoo(): void {}
}
class ChildFoo extends Foo{
private function testFoo(): void {}
}
This was not allowed prior to PHP 8.0, and resulted in a fatal error:
Fatal error: Cannot override final method Foo::testFoo() in ... on line ...
In PHP 8.0 and later, this restriction is removed, and only a warning is emitted:
Warning: Private methods cannot be final as they are never overridden by other classes in ... on line ...
Note that this warning is emitted when a class declares a method as final private
; not when a child class re-declares a private
method.
final private
class constructors
An exception is made for the warning mentioned above for class constructors. It is possible to declare a class constructor as final private
:
class Foo {
final private function __construct() {}
}
Attempting to re-declare the constructor results in the same fatal error in all PHP versions.
class Foo {
final private function __construct() {}
}
class ChildFoo extends Foo{
final private function __construct() {}
}
// Fatal error: Cannot override final method Foo::__construct() in ... on line ...
static
methods
Changing the static
flag in an inheritance was not allow prior to PHP 8.0. It is allowed in PHP 8.0.
class Foo {
private function bar() {}
static private function baz() {}
}
class ChildFoo extends Foo{
static private function bar() {} // Adds `static` flag from Foo
private function baz() {} // Removes `static` flag from Foo
}
Prior to PHP 8.0, this caused fatal errors:
Fatal error: Cannot make non static method Foo::bar() static in class ChildFoo in ... on line ...
Fatal error: Cannot make static method Foo::baz() non static in class ChildFoo in ... on line ...
abstract
methods
PHP does not allow to declare a private abstract function
in any PHP version. In PHP 8.0 and later, it is allowed to declare a method as abstract
even if a method with same name exists in the parent class.
class Foo {
private function test() {}
}
abstract class ChildFoo extends Foo{
abstract protected function test();
}
Prior to PHP 8.0, this resulted in a fatal error:
Fatal error: Cannot make non abstract method Foo::test() abstract in class ChildFoo in ... on line ...
Magic Methods
In PHP 8.0, magic method signatures are enforced. Magic methods (e.g __get
, __set
, __callStatic
, etc) must follow the signature even if they are declared private
.
Backwards Compatibility Impact
All private method signature patterns were not allowed and resulted in a fatal error in PHP versions prior to 8.0. As PHP 8.0 now allows it, these changes should not cause further errors in PHP 8.0
Declaring a class method final private
emits a PHP warning at the declaration time of the parent class. This behavior is different from the fatal error that is only triggered if a child class attempted to extend/re-declare the same method.
Related Changes
- Fatal errors on incompatible method signatures
- Class magic method signatures are strictly enforced
- Calling non-static class methods statically result in a fatal error