In PHP 8.1, the following code, which worked in previous versions:
class Example implements Countable {
public function count() {
return 42;
}
}
Raises a deprecation notice:
Deprecated: Return type of Example::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
What does this mean, and how should I fix it?
Since PHP 7.0, it has been possible to specify the return type of a function or method, such as function example(): string
to indicate a function that returns a string. This forms a contract that other code can rely on.
For instance, this class promises that the getList
method will return some kind of Iterator
:
class Base {
public function getList(): Iterator {
// ...
}
}
Calling code can be written knowing that if $foo instanceOf Base
is true, then $foo->getList() instanceOf Iterator
will also be true.
If you extend the class, you can specify the same return type, or a more specific return type (a rule known as "covariance"), and the calling code's assumption will still be true:
class SubClass extends Base {
public function getList(): DirectoryIterator {
// ...
}
}
$foo = new SubClass;
var_dump($foo instanceOf Base); // true
var_dump($foo->getList() instanceOf Iterator); // true
But if you specify a different return type, or no return type at all, the assumption breaks, so PHP won't allow you to do it:
class NotPossible extends Base {
public function getList(): bool {
return false;
}
}
// Fatal error: Declaration of NotPossible::getList(): bool must be compatible with Base::getList(): Iterator
// If the error didn't happen...
$foo = new NotPossible;
var_dump($foo instanceOf Base); // would be true
var_dump($foo->getList() instanceOf Iterator); // would be false!
If you add a return type to an existing class or interface, every class extending or implementing must also be changed, or it will give the same error as in the NotPossible
example above.
With the addition of Union Types in PHP 8.0, the return types of most internal functions and methods can be specified; but specifying it for any class or interface method not marked final
would have immediately broken a lot of code.
So, instead, the concept of a "tentative" return type was added: the correct return types were documented, but what would normally be an error is instead the deprecation notice shown in the question.
#[\ReturnTypeWillChange]
attributeThe extra problem is that a lot of code needs to be able to run on multiple versions of PHP, and some of the added return types aren't valid in versions before 8.0. So, to indicate a planned change to the returned type in your code, you can add the special attribute #[\ReturnTypeWillChange]
. This looks like a comment to older versions of PHP, but tells PHP 8.1 not to raise the deprecation notice. Then, once you don't need to support older versions of PHP, you can fix the return type.
Firstly, read the message carefully to find out which method you need to change, and what the correct return type is. In the example above:
Return type of Example::count() ...
This says the count
method on the Example
class needs changing ...
... should either be compatible with Countable::count(): int ...
... and the expected return type is int
, as defined on the Countable
interface
Next, decide what you can do:
42
is valid for a return type of int
.extend
this one. If you're working on library code where users might have extended this class, you will need to consider the impact on them.If you decide it's safe, you can simply add the return type as shown in the notice:
class Example implements Countable {
public function count(): int {
return 42;
}
}
If you need to support older versions of PHP, or users who won't have updated their code yet, you can temporarily suppress the notice:
class Example implements Countable {
#[\ReturnTypeWillChange]
public function count() {
return 42;
}
}
It's important to note that the internal return types will probably be enforced in PHP 9.0, so make sure you have a solid plan to change methods you mark with this attribute.