PHP 8.0: Fatal errors on incompatible method signatures

Version8.0
TypeChange

Prior to PHP 8, PHP was inconsistent the way it handled method signature checks when a parent class was extended.

Extending class methods

class Foo {
    public function process(stdClass $item): array{}
}

class SuperFoo extends Foo{
    public function process(array $items): array{}
    //                      ^^^^^ mismatch
}

In the snippet above, SuperFoo::process method has a mismatching signature to its parent Foo. This is a clear violation of Liskov Substitution Principle (LSP), but PHP only raised warning:

Warning: Declaration of SuperFoo::process(array $items): array should be compatible with Foo::process(stdClass $item): array in ... on line ...

In PHP 8, such signature mismatches result in fatal error.

Fatal error: Declaration of SuperFoo::process(array $items): array must be compatible with Foo::process(stdClass $item): array in ... on line ...

Note that this fatal error will only be triggered if it violates LSP. Changing the type of method signatures is allowed as long it follows LSP.

Implementing abstract trait methods

Prior to PHP 8, PHP did not enforce any signature checking when a trait method is extended. In PHP 8.0 and later, abtract methods with mismatching signatures will fail with a fatal error.

trait Foo {
    abstract public function inParams(stdClass $item): array;
    abstract public function inReturn(stdClass $item): int;
}

class SuperFoo{
    use Foo;
    public function inParams(array $items): array{}
    //                       ^^^^^ Mismatch
    public function inReturn(stdClass $item): int{}
    //                                        ^^^ Mismatch
}

In PHP 8, the snippet above will result in a fatal error:

Fatal error: Declaration of SuperFoo::inParams(array $items): array must be compatible with Foo::inParams(stdClass $item): array in ... on line ...

Note that this fatal error will only be triggered if it violates LSP. Changing the type of method signatures is allowed as long it follows LSP.

PHP LSP enforcement

This change will finally bring PHP 8 to actively enforce signature checks on all extent/implement patterns:

The following chart describes how PHP versions prior to 8.0 enforced signature mismatches, and how it changes in PHP 8

PHP <8 PHP >=8
class implements interface: method parameters Fatal Error Fatal Error
class implements interface: return type Fatal Error Fatal Error
class extends abstract method: method parameters Fatal Error Fatal Error
class extends abstract method: return type Fatal Error Fatal Error
class extends class: Method parameters Warning Fatal Error
class extends class: Method return type Fatal Error Fatal Error
trait use and extend: Method parameters none none
trait use and extend: Method return type none none
trait use and implement: abstract Method parameters none Fatal Error
trait use and implement: abstract Method return type none Fatal Error

Backwards compatibility impact

If you had classes that extended a parent class with mismatching signatures, they will now fail with a fatal error. Prior PHP 8, those errors raised a warning.

If your PHP 7 code base does not raise such warnings, you will be able to upgrade to PHP 8 without problems. Fixing the code for PHP 8 will fix the warning in PHP 7 as well.

abtract trait method mismatches did not emit any warnings whatsoever in any PHP versions prior to PHP 8, and they will fail with a fatal error in PHP. As pointed in a Reddit discussion, this change can introduce unexpected errors that are not currently detected by any code analysis tools because that was technically allowed.

Symfony, for example, used this pattern that needed to be fixed.


Class method fatal errors

RFC Discussion Implementation

abstract trait method fatal errors

RFC Discussion Implementation