Php 将接口传递给另一个接口方法
我需要在OOP中实现一个事件侦听器模型。现在我有了Php 将接口传递给另一个接口方法,php,oop,covariance,contravariance,php-7.4,Php,Oop,Covariance,Contravariance,Php 7.4,我需要在OOP中实现一个事件侦听器模型。现在我有了EventInterface和ListenerInterface。但我想将事件传递给侦听器,如下所示: interface ListenerInterface { public function listen(EventInterface $event); } 但是,即使我传递给侦听器的事件实现了EventInterface,我也不能这样做。那我该怎么办?我想把它抽象成简单的用法 PhpStorm的屏幕截图: 您的SendUserNotif
EventInterface
和ListenerInterface
。但我想将事件传递给侦听器,如下所示:
interface ListenerInterface {
public function listen(EventInterface $event);
}
但是,即使我传递给侦听器的事件实现了EventInterface
,我也不能这样做。那我该怎么办?我想把它抽象成简单的用法
PhpStorm的屏幕截图:
您的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;
}
任何实现原始HandlerInterface
的类都需要严格遵循它
例如
如果您试图使实现在参数上使用协方差,它将失败,因为实现将不遵循接口。例如
class WrongOriginalImplementor implements OriginalHandlerInterface
{
public function handle(ChildInterface $a) : string
{
return class_name($a);
}
}
这样做的逻辑简单而合理。如果有人正在使用您创建的类,该类声明实现了OriginalHandlerInterface
,那么该用户根本不需要查看您的实现,他们只需要查看接口
如果原始接口声明handle()
需要一个ParentInterface
对象,这意味着我可以将实现ParentInterface
的类中的对象传递给它,但实现ChildInterface
或另一个ChildInterface
的类中的对象也将有效
另一方面,如果您的实现能够说handle(ChildInterface$a)
,那么用户的期望就会被背叛,因为他们将无法从实现另一个ChildInterface的类中传递handle()
对象,尽管根据原始HandlerInterface
有效
另一方面,如果您有此接口:
interface AnotherHandlerInterface
{
public function handle(ChildInterface $a): string;
}
您的实现可以在handle()
参数上使用逆变。他们可以指定限制较少的参数类型。例如:
此实现,尽管不遵循点,是有效的。同样,如果您考虑一下,同样的逻辑也适用:您的类的使用者可以查看另一个HandlerInterface
,并看到handle()
需要一个ChildInterface
。因此,如果用户遵循原始合同,他们将永远不会被您的实现绊倒
您的实现限制较少,并且接受原始接口不会接受的对象,但这很好,因为协方差和逆变规则允许这样做
请注意,协方差和逆变支持在PHP中是非常新的
您可以看到上面的代码正在运行(包括错误)您应该能够做到这一点。为什么你认为你不能呢?也给它一个接口名。只要您传入的对象实现了该接口,您就可以了。UserLoggeDiEvent应该实现ListenerInterface,这就是消息所说的,只要它不符合逻辑,那么您应该再次检查逻辑,因为屏幕截图中的代码与界面显示中的代码不匹配。在您显示的代码中,接口仅声明方法
listen()
,但在您的屏幕截图中,它抱怨方法\uu construct()
的签名。请为这个例子添加适当的代码(实际的接口和实现类)作为代码,而不是屏幕截图,这样我可以给你一个正确的答案。@Alexosipov,问题已经解决了,但如果你能用正确的代码更新它,那就太好了。此外,对于以下答案的反馈,我们将不胜感激。
interface AnotherHandlerInterface
{
public function handle(ChildInterface $a): string;
}
class ContravariantImplementor implements AnotherHandlerInterface
{
public function handle(ParentInterface $a): string {
return class_name($a);
}
}