1

我的项目在 PHP 7.X 上运行良好,升级到 PHP 8 后出现以下问题,我不知道如何解决。

我有以下(简化的)情况:

<?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);
    }
}

我的整个项目都是这样运行的,但是从 PHP 8 开始,我得到了该行的异常

public function output(Car $entity)

带有“致命错误:*** 的声明必须与 *** 兼容”

它与 PHP 7 完美配合!因为“车”也是交通工具。

有人知道如何解决这个问题吗?

谢谢!

4

2 回答 2

3

您收到警告并且现在出现致命错误的原因是您的代码不遵守子类型中方法参数类型逆变的Liskov 替换原则 (LSP)标准要求。

考虑到这一点,问题是虽然子类中的方法可以扩展参数类型的范围,但它必须接受父类接受的所有参数类型。

您的子类CarOutputMaker违反了此规则,它的方法output()接受类型参数Car(的子类型),但不接受父方法中声明Vehicle的超类型参数。VehicleVehicleOutputMaker::output()

所以这在 PHP7 中是有效的:

class VehicleOutputMaker  
{  
    public function output(Vehicle $entity)  
    {  
    }  
}  
  
class CarOutputMaker extends VehicleOutputMaker  
{  
    public function output(Vehicle $entity)  
    {  
        parent::output($entity);  
    }  
}

值得注意的是,由于您使用的是 PHP8,因此您可以使用联合类型对子类中的两种类型进行类型提示:Vehicle|Car.

class VehicleOutputMaker  
{  
    public function output(Vehicle $entity)  
    {  
    }  
}  
  
class CarOutputMaker extends VehicleOutputMaker  
{  
    public function output(Vehicle|Car $entity)  
    {  
        parent::output($entity);  
    }  
}
于 2020-12-30T17:57:35.730 回答
1

为什么不将 Car 的类型提示更改为 Vehicle,因为这样就尊重了父类的方法签名。

然后,如果您想执行 Car 特定行为,则必须在 CarOutputMaker 的输出方法中键入 check 并将 Vehicle 类型转换为 Car。

class CarOutputMaker extends VehicleOutputMaker
{
    //THROWS EXCEPTION
    public function output(Vehicle $entity)
    {
        parent::output($entity);
    }
}
于 2020-12-29T15:36:09.193 回答