Foo 是具有特定方法的基類。大多數這些方法使用相同的型別(例如:)Foo::setNext(self $foo)。
我想創建擴展 Foo 的類,并且只允許使用與它們自己嚴格相同的型別(Extend1Foo 型別的物件不能與 Extend2Foo 型別的物件一起使用)。
在下面的代碼中,由于回傳型別是靜態的,getBar()會引發錯誤。這就是我想要的。
但是,setBar()由于self引數型別,允許接收任何 Foo 實體作為引數。
可復制的例子:
class Foo
{
private ?self $bar = null;
public function getBar(): static {
return $this->bar;
}
public function setBar(self $object): void {
$this->bar = $object;
}
}
class Foo1 extends Foo { /* specific methods */ }
class Foo2 extends Foo { /* specific methods */ }
$foo1 = new Foo1;
$foo1->setBar(new Foo2); // <<< No TypeError, but I want it.
$foo2 = $foo1->getBar(); // <<< Got error, I'm OK.
我已經強制 TypeError :
public function setBar(self $object): void
{
if (get_class($object) != static::class) {
throw new TypeError(
sprintf('%s::%s(): Parameter value must be of type %s, %s given',
__class__, __function__,
static::class, get_class($object)
)
);
}
$this->child = $object;
}
并使用:
$foo1 = new Foo1;
$foo1->setBar(new Foo2); // TypeError : Foo::setBar(): Parameter value must be of type Foo1, Foo2 given
這是預期的行為。
我的問題是:
有沒有辦法避免這種對型別的動態測驗?我認為static不能在引數中使用 ,而不是self,比如public function setBar(static $object)。
uj5u.com熱心網友回復:
您的用例在PHP RFC 中static被明確考慮和拒絕,它在 return position 中添加了型別注釋,因為允許它會破壞繼承點:
該
static型別只允許在回傳型別內部,它也可能作為復雜型別運算式的一部分出現,例如?staticorstatic|array。要理解為什么
static不能用作引數型別(除了從實際角度來看這沒有什么意義),請考慮以下示例:class A { public function test(static $a) {} } class B extends A {} function call_with_new_a(A $a) { $a->test(new A); } call_with_new_a(new B);在 Liskov 替換原則 (LSP) 下,我們應該能夠在
B任何需要類的地方替換類A。然而,在這個例子中,傳遞B而不是A會拋出 aTypeError,因為B::test()不接受 aA作為引數。更一般地說,
static僅在協變背景關系中是合理的,目前僅是回傳型別。
另一方面,可以將你想要的介面封裝在一個 trait 中,這就是 PHP 所說的 mixin:
trait Bar {
private ?self $bar = null;
public function getBar(): static {
return $this->bar;
}
public function setBar(self $object) {
$this->bar = $object;
}
}
class Foo {}
final class Foo1 extends Foo { use Bar; }
final class Foo2 extends Foo { use Bar; }
try {
$foo1 = new Foo1;
$foo1->setBar(new Foo2); // TypeError
}
catch (Throwable $error)
{
echo $error->getMessage(), PHP_EOL;
}
通過這種方式,公共方法將不會成為Foo類介面的一部分,但這可能是最好的,因為按照上述方式,無法為其賦予有意義的型別簽名。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/396407.html
