我需要在 OOP 中实现事件侦听器模型。现在我有EventInterface
和ListenerInterface
。但我想将事件传递给侦听器,如:
interface ListenerInterface {
public function listen(EventInterface $event);
}
但即使Event
我传递给 Listener implements ,我也不能这样做EventInterface
。那我该怎么办?我想把它抽象化以方便使用。
我需要在 OOP 中实现事件侦听器模型。现在我有EventInterface
和ListenerInterface
。但我想将事件传递给侦听器,如:
interface ListenerInterface {
public function listen(EventInterface $event);
}
但即使Event
我传递给 Listener implements ,我也不能这样做EventInterface
。那我该怎么办?我想把它抽象化以方便使用。
您SendUserNotificationListener
不遵守由ListenerInterface
.
该错误有助于告诉您这一点。如果您尝试运行此代码,您将收到一个致命错误并且您的脚本将崩溃。
如果你有几个这样的接口:
interface ParentInterface {
public function foo();
}
interface ChildInterface extends ParentInterface {
public function bar();
}
interface AnotherChildInterface extends ParentInterface {
public function baz();
}
interface OriginalHandlerInterface
{
public function handle(ParentInterface $a): string;
}
任何实现的类都OriginalHandlerInterfce
需要完全遵循它
例如
class OriginalImplementor implements OriginalHandlerInterface
{
public function handle(ParentInterface $a) : string
{
return class_name($a);
}
}
如果你试图让实现在参数上使用协方差,它会失败,因为实现不会遵循接口。例如
class WrongOriginalImplementor implements OriginalHandlerInterface
{
public function handle(ChildInterface $a) : string
{
return class_name($a);
}
}
这样做的逻辑简单而合理。如果有人正在使用您创建的声明该 implements 的类OriginalHandlerInterface
,则该用户根本不需要查看您的实现,他们只需要查看接口即可。
如果原始接口声明handle()
需要一个ParentInterface
对象,这意味着我可以将来自实现的类的对象传递给它ParentInterface
,但来自实现ChildInterface
或的类的对象AnotherChildInterface
也是有效的。
另一方面,如果您的实现能够说handle(ChildInterface $a)
,那么用户将背叛他们的期望,因为他们将无法handle()
从实现的类中传递对象AnotherChildInterface
,尽管根据OriginalHandlerInterface
.
另一方面,如果你有这个界面:
interface AnotherHandlerInterface
{
public function handle(ChildInterface $a): string;
}
您的实现可以在参数上使用逆变。handle()
他们可以指定限制较少的参数类型。例如:
class ContravariantImplementor implements AnotherHandlerInterface
{
public function handle(ParentInterface $a): string {
return class_name($a);
}
}
这个实现,尽管不遵循点,是有效的。同样,如果您考虑一下,同样的逻辑也适用:您的班级的消费者可以查看AnotherHandlerInterface
并看到handle()
预期的ChildInterface
. 因此,如果遵循原始合同,他们将永远不会被您的实施绊倒。
您的实现限制较少,并接受原始接口不接受的对象,但这很好,因为协变和逆变规则允许它。
请注意,协变和逆变支持在 PHP 中是相当新的,并且仅在 PHP 7.4 中添加。
你可以看到上面的代码在这里工作(包括错误)