我需要在OOP中实现事件监听器模型。现在我有EventInterface
和ListenerInterface
。但我想将事件传递给侦听器,如:
interface ListenerInterface {
public function listen(EventInterface $event);
}
但是即使我传递给侦听器的Event
实现了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);
}
}
如果您尝试使实现在parameter上使用covariance,则它将失败,因为实现不会遵循该界面。例如:
class WrongOriginalImplementor implements OriginalHandlerInterface
{
public function handle(ChildInterface $a) : string
{
return class_name($a);
}
}
此逻辑简单而合理。如果有人使用您声明的实现OriginalHandlerInterface
的类,则该用户根本不需要查看您的实现,只需查看接口即可。
如果原始接口声明handle()
需要一个ParentInterface
对象,则意味着我可以从实现ParentInterface
的类中传递对象,但是来自实现ChildInterface
或AnotherChildInterface
的类中的对象也将是有效的。
[另一方面,如果您的实现能够说出handle(ChildInterface $a)
,那么用户就会背弃他们的期望,因为尽管他们无法从实现handle()
的类中传递AnotherChildInterface
对象,根据OriginalHandlerInterface
有效。
另一方面,如果您具有此界面:
interface AnotherHandlerInterface
{
public function handle(ChildInterface $a): string;
}
您的实现可以在handle()
参数上使用contravariance。他们可以指定较少限制参数类型。例如:
class ContravariantImplementor implements AnotherHandlerInterface
{
public function handle(ParentInterface $a): string {
return class_name($a);
}
}
此实现,尽管未跟在圆点后面,有效。同样,如果您考虑采用相同的逻辑:类的使用者可以查看AnotherHandlerInterface
并看到handle()
期望ChildInterface
。因此,如果遵循原始合同,您的实施将永远不会绊倒他们。
您的实现没有那么严格的限制,并且可以接受原始接口不会接受的对象,但这很好,因为协变和逆变的规则允许它。
请注意,协方差和对数支持在PHP and has been added only in PHP 7.4中是相当新的。
您可以看到上面的代码在工作here(包括错误)