您的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);
}
}
这样做的逻辑简单而合理。如果有人在使用您创建的类并声明实现了OriginalHandlerInterface,那么该用户根本不需要查看您的实现,他们只需要查看接口即可。
如果原始接口声明 handle() 需要一个 ParentInterface 对象,这意味着我可以将实现 ParentInterface 的类中的对象传递给它,但实现 ChildInterface 或 AnotherChildInterface 的类中的对象也将是有效。
另一方面,如果您的实现能够说出handle(ChildInterface $a),那么用户的期望就会被背叛,因为他们将无法从实现AnotherChildInterface的类中传递handle()对象,尽管根据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 中是相当新的,and has been added only in PHP 7.4。
你可以看到上面的代码工作here(包括错误)