为了账号安全,请及时绑定邮箱和手机立即绑定

声明与接口不兼容 (PHP)

声明与接口不兼容 (PHP)

PHP
九州编程 2023-09-08 16:37:43
假设我有一个父类和两个这样的子类abstract class Vehicle {    public function setManufacturer(string $manufacturer) { ... }}class Bicycle extends Vehicle {    public function addSaddle() { ... }}class Car extends Vehicle {    public function setSpeedLimit(float $limit) { ... }}现在我想通过这样的接口使用这些对象interface VehicleInterface {    public function create(Vehicle $vehicle);}class BicycleService implements VehicleInterface {    public function create(Bicycle $bicycle) {        $bicycle->setManufacturer('Some company'); // Common for all Vehicle objects        $bicycle->addSaddle(); // Common only for Bicycle objects    }}看来这是不可能的,因为BicycleService create(...)与接口不兼容。除了删除类型提示之外,还有什么办法可以解决这个问题吗?
查看完整描述

4 回答

?
紫衣仙女

TA贡献1839条经验 获得超15个赞

当你在班级中实施时,你必须遵守合同。因此,无论对实现进行分类,该类都Vehicle 必须具有setManufacturer您声明的方法。



查看完整回答
反对 回复 2023-09-08
?
守候你守候我

TA贡献1802条经验 获得超10个赞

考虑一下:


class NotBicycle implements Vehicle { ... }


interface VehicleInterface {

    public function create(Vehicle $vehicle);

}


class BicycleService implements VehicleInterface {

    public function create(Bicycle $bicycle) {

        $bicycle->setManufacturer('Some company'); // Common for all Vehicle objects

        $bicycle->addSaddle(); // Common only for Bicycle objects

    }

}


function createVehicle(VehicleInterface $service, Vehicle $vehicle) {

    $service->create($vehicle);

}

$service = new BicycleService();

$vehicle = new NotBicycle();

createVehicle($service, $vehicle);

即使你以某种方式只能接受Bicycle其中的一个BicycleService,createVehicle($service, $vehicle)仍然会起作用,因为VehicleInterface有一个方法create(Vehicle $vehicle)。因此,为了让它按照您想要的方式工作,您需要从根本上打破界面的本质。


您唯一真正的选择是添加运行时类型检查。就像例如


class BicycleService implements VehicleInterface {

    public function create(Vehicle $bicycle) {

        if (!$bicycle instance of Bicycle) { 

           throw new TypeError('Expected Bicycle but got '.get_class($bicycle)); 

        }

        $bicycle->setManufacturer('Some company'); // Common for all Vehicle objects

        $bicycle->addSaddle(); // Common only for Bicycle objects

    }

}

您尝试做的事情称为协变方法参数类型,在大多数面向对象的编程语言中是不允许的,因为它违反了里氏替换原则


查看完整回答
反对 回复 2023-09-08
?
30秒到达战场

TA贡献1828条经验 获得超6个赞

Bicycle您需要删除带有 的类型Vehicle。你可能需要检查if ($bicycle instanceof Bicycle)

抽象层次太抽象了。

查看完整回答
反对 回复 2023-09-08
?
慕尼黑的夜晚无繁华

TA贡献1864条经验 获得超6个赞

您需要将您的Vehicle类传递给它,然后用于instanceof检查接口。在下面的例子中,我更改了命名约定。


interface Vehicle {

    public function setSpeedLimit(Float $limit) : Car;

    public function setManufacturer(String $manufacturer) : MethodOfTransport;

}


interface NonVehicle {

    public function addSaddle() : Bicycle;

    public function setManufacturer(String $manufacturer) : MethodOfTransport;

}


abstract class MethodOfTransport

{

    public function setManufacturer(String $manufacturer) : MethodOfTransport { return $this; }

}


class Bicycle extends MethodOfTransport implements NonVehicle

{

查看它在 3v4l.org 上的运行情况


}


class Car extends MethodOfTransport implements Vehicle

{

    public function setSpeedLimit(Float $limit) : Car { return $this; }

}


$b = new Bicycle();

$c = new Car();

如前所述,我消除了命名约定的一些混乱,因为 aBicycle不是 aVehicle而是 a MethodOfTransport。


interface VehicleServiceInterface

{

    # Change the return DataType to MethodOfTransport if Vehicle implements multiple classes

    public function create(MethodOfTransport $t) : Car;

}


class VehicleService implements VehicleServiceInterface

{

    public function create(MethodOfTransport $t) : Car

    {

        if (!$t instanceof Vehicle)

            throw new Exception( 'Cannot create a Vehicle on a NonVehicle instance.' );

            

        $t->setManufacturer( 'Foo' )->setSpeedLimit( 140 );

        return $t;

    }

}


$c = (new VehicleService())->create( $c ); // Works

$b = (new VehicleService())->create( $b ); // Throws Exception

和Car都是Bicyclea MethodOfTransport,但是,一个是 a Vehicle,另一个是 a NonVehicle。两者都可以传递到方法中,但我们可以使用 来确保它是正确的类型instanceof。


但是,您可以将返回类型设置为方法的返回类型,create因为Car我们Vehicle在本例中仅过滤实例。如果您有多个Vehicle已实现的类,请将其更改为返回MethodOfTransport


查看它在 3v4l.org 上的运行情况



查看完整回答
反对 回复 2023-09-08
  • 4 回答
  • 0 关注
  • 127 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信