My project is running fine on PHP 7.X and after upgrading to PHP 8 I have the following problem and I don't know how to fix this.
I have a the following (simplified) situation:
<?php
class Vehicle
{
//...
}
class Car extends Vehicle
{
//...
}
class VehicleOutputMaker
{
public function output(Vehicle $entity)
{
}
}
class CarOutputMaker extends VehicleOutputMaker
{
//THROWS EXCEPTION
public function output(Car $entity)
{
parent::output($entity);
}
}
My whole project is running like this but since PHP 8 I get an exception for the line
public function output(Car $entity)
with "FATAL ERROR: Declaration of *** must be compatible with ***"
It worked perfectly well with PHP 7! Because "Car" is also a Vehicle.
Somebody has an idea how to fix this?
Thanks!
The reason you got a warning and now a fatal error is due to the fact that your code doesn't respect the Liskov substitution principle (LSP) standard requirement of contravariance of method parameter types in the subtype.
With this in mind, the issue is that while a method in a sub-class can expand the range of parameter types, it must accept all parameter types that the parent class accepts.
Your sub-class CarOutputMaker
breaks this rule, its method output()
accepts a parameter of type Car
(a sub-type of Vehicle
), but not a parameter of super-type Vehicle
as declared in its parent method VehicleOutputMaker::output()
.
So this would be valid in PHP7:
class VehicleOutputMaker
{
public function output(Vehicle $entity)
{
}
}
class CarOutputMaker extends VehicleOutputMaker
{
public function output(Vehicle $entity)
{
parent::output($entity);
}
}
Noteworthy, since you're using PHP8, you can use union types to type-hint both types in your sub-class: Vehicle|Car
.
class VehicleOutputMaker
{
public function output(Vehicle $entity)
{
}
}
class CarOutputMaker extends VehicleOutputMaker
{
public function output(Vehicle|Car $entity)
{
parent::output($entity);
}
}