Abstract function parameter type hint overriding in PHP 7
Is it possible to override an abstract function in PHP 7 with a function in a child class that would narrow down on the accepted argument type?
A word of elaboration - let's assume that I have an abstract method:
abstract public function setTarget(
AbstractDeliveryTarget $deliveryTarget
): Delivery;
Now in one child class, I'd like to override this method's signature in order for it to accept only a specific parameter type (let's assume thatEmailDeliveryTarget
extendsAbstractDeliveryTarget
):
public function setTarget(
EmailDeliveryTarget $emailDeliveryTarget
): Delivery;
PHP interpreter would then complain that the signature of the abstract method cannot be altered in the child class. Is there, then, a way to achieve that type-safety in a child class other than some in-method-body type guards?
Answer
Solution:
This is not a technical limitation; what you're asking for doesn't make sense with the principles of OOP.
Your abstract class is a contract; let's define the base class:
And some delivery targets
Then you can write this somewhere else:
Because we know that
$d
is anAbstractDeliverer
, we know that passing$e
and$s
to it should both work. That is the contract guaranteed to us when we made sure our input was of that type.Now lets see what happens if you extend it the way you wanted:
We know that
$e instanceOf AbstractDeliverer
will betrue
, because we've inherited, so we know we can safely call ourdeliverAll
method:The first part of the function is fine, and will effectively run this:
But then we hit this part:
Oops! Fatal error! But the contract on
AbstractDeliverer
told us this was the correct value to pass! What went wrong?The rule is that a sub-class must accept all inputs that the parent class would accept, but it can accept additional inputs if it wants, something known as "contravariance". (Return types are instead "covariant": the sub-class must never return a value which couldn't be returned from the parent class, but can make a stronger promise that it will only return a subset of those values; I'll leave you to come up with an example of that one yourself).
Answer
Solution:
Looks like no pretty solutions so we can try use interfaces.
OR
Depends on what you want to do.