尝试在子项中使用属性总是会失败并出现以下错误:
致命错误:D::$prop 的类型必须是 A(如 C 类)
我读过有关https://www.php.net/manual/en/language.oop5.variance.php但这仍然很令人困惑,我真的找不到一个合乎逻辑的理由来阻止这样做东西。
无法使用实现接口的类并尊重该接口的约定而无法键入提示,这感觉非常不自然和令人沮丧。
比如下面的例子:
<?php
interface A {
public function foo();
}
class B implements A {
public function foo() {
echo "foo";
}
public function bar() {
echo "bar";
}
}
class C {
public function __construct(protected A $prop) {
$this->prop->foo();
}
}
class D extends C {
public function __construct(protected B $prop) { // This can't be done even though B implements A interface !!!
$this->prop->bar();
parent::__construct($prop);
}
}
$b = new B();
$d = new D($b);
我需要理解为什么它不可能,并有一个有效的例子来说明为什么它不能以这种方式运行,尽管这段代码看起来完全符合逻辑。
假设您的代码可行,请考虑以下场景:
class C {
public function setProp(A $prop) {
$this->prop = $prop;
}
}
class D extends C {
public function getProp() : B {
return $this->prop;
}
}
class E implements A {}
$e = new E();
$d->setProp($e);
$e = $d->getProp(); # Should return an instance of B
# but it will return an instance of E.
显然,这是出乎意料的。因此 PHP 不允许您重新声明不同类型的属性。
你可以做的就是在构造函数中定义参数类型。如果你需要B的成员提示,你可以声明另一个方法。
class D extends C {
public function __construct(B $prop) { # No protected
parent::__construct($prop);
$this->prop->bar(); # This is legal, but your IDE may complain
$this->getProp()->bar();
}
protected function getProp() : B {
return $this->prop;
}
}