interface I1 {
public function one();
}
interface I2 {
public function two();
}
class C2 {
public function __construct( I1&I2 $injected ) {
// Both calls are guaranteed to be valid
$injected->one();
$injected->two();
}
}
class C1 implements I1, I2 {
public function one() { ... }
public function two() { ... }
}
new C2( new C1 ); // passes the check, because it implements both interfaces
interface I1 {
public function one();
}
interface I2 {
public function two();
}
interface I1and2 extends I1, I2 {}
class C2 {
public function __construct( I1and2 $injected ) {
// Both calls are guaranteed to be valid
$injected->one();
$injected->two();
}
}
class C1 implements I1and2 {
public function one() { ... }
public function two() { ... }
}
new C2( new C1 ); // passes the check
interface I1 {
public function one();
}
interface I2 {
public function two();
}
class C2 {
public function __construct( I1 $injected1, I2 $injected2 ) {
// Valid call on any I1 instance
$injected1->one();
// Valid call on any I2 instance
$injected2->two();
}
}
class C1 implements I1, I2 {
public function one() { ... }
public function two() { ... }
}
$something = new C1;
new C2( $something, $something ); // passes both checks
1条答案
按热度按时间hsvhsicv1#
让我们把它做得更具体一点:
请注意,我在这里没有显示接口
I2
或类C1
,因为类C2
中没有任何内容表明它们是相关的。这个工具告诉你的是,* 只看类
C2
的定义 *,没有办法知道$injected->two()
是一个有效的方法调用-我们唯一确定$injected
拥有的方法是one()
,因为我们知道它实现了接口I1
。在实践中,你总是传递一个有更多方法的对象,并实现一个额外的接口,这一事实在
C2
类中根本没有记录。解决这个问题的方法是向
C2
添加更多信息,即传递的对象必须实现 *I1
* 和 *I2
:这种类型(
I1&I2
)中包含&
的语法被称为“交集类型”,与更常见的“联合类型”语法相反,例如I1|I2
意味着“必须实现I2
和I2
中的至少一个”。交叉类型是在PHP 8.1中添加的。如果你需要你的代码在旧版本上工作,这有点麻烦,但可以通过引入一个继承两个现有接口的新接口来实现。区别在于类
C2
必须显式实现这个新接口才能通过检查:或者,如果你的两个接口实际上代表了类
C2
恰好覆盖的两个单独的功能,但是 * 可能 * 被单独的对象覆盖,你可以只使用两个参数,每个参数定义一个必需的接口:请记住,在每种情况下,首先使用接口的目的是记录代码的“不变属性”,而不是你碰巧拥有的实现。