4 回答

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
? ? }
}
您嘗試做的事情稱為協變方法參數類型,在大多數面向對象的編程語言中是不允許的,因為它違反了里氏替換原則

TA貢獻1828條經驗 獲得超6個贊
Bicycle
您需要刪除帶有 的類型Vehicle
。你可能需要檢查if ($bicycle instanceof Bicycle)
抽象層次太抽象了。

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
{
}
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
- 4 回答
- 0 關注
- 179 瀏覽
添加回答
舉報