是否可以在PHP接口中使用不同的参数定义方法?

Khr*_*riz 10 php dependency-injection interface

我正在开发一个注入Logger对象的服务,但我可以使用2种不同类型的记录器,我正计划使用syslog记录器和队列消息系统记录器.这可能吗?

想法是有一个界面:

interface Loggable
{
    public function log() ;
}
Run Code Online (Sandbox Code Playgroud)

和2个实现该接口的类:

class Syslogger implements Loggable
{
    public function log()
    {
        ...
    }
}

class QMSLogger implements Loggable
{
    public function log($queueName)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以使用的唯一方法是将一个数组作为参数并在一个类上使用它而不是在另一个类上使用...但这有点臭:P

dec*_*eze 15

如评论中所述,这不是相同的界面.如果您无法在所有可能的记录器实现中概括接口,请将配置差异作为实例构造函数的一部分:

class QMSLogger implements Loggable {

    protected $queueName;

    public function __construct($queueName) {
        $this->queueName = $queueName;
    }

    public function log() {
        ...
    }

}
Run Code Online (Sandbox Code Playgroud)


Mat*_*oli 14

你问是否有可能:是的,但......

如果实现接口,则必须遵守其合同.

interface Loggable
{
    public function log();
}
Run Code Online (Sandbox Code Playgroud)

这个接口的合约是你可以log()不带任何参数调用.

为了尊重这一点,您可以使参数可选:

class QMSLogger implements Loggable
{
    public function log($queueName = null)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这是完全有效的PHP,它尊重Liskov替换原则.当然,在对接口进行编码时,不得使用该可选参数,否则您显然会破坏接口.只有在使用实现时(例如,在紧密耦合的代码的某些部分),此类参数才有用QMSLogger.

然而,这可能不是您的问题的解决方案,因为它$queueName似乎是一个配置值,并且最好将它传递给类的构造函数(如另一个答案中所述).


小智 12

我遇到了一个类似的情况,我想创建一个接口,简单地确保实现它的任何类都具有相同名称的方法,但允许使用不同的参数实现。

/**
 * Interface Loggable
 * @method log
 */
interface Loggable
{

}
Run Code Online (Sandbox Code Playgroud)

现在 Loggable 接口可以使用不同的参数来实现,如下所示。

class Syslogger implements Loggable
{
    public function log($key, $value)
    {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这实际上是最好的答案(恕我直言)。这种类型的模式称为[鸭子打字](https://en.wikipedia.org/wiki/Duck_typing)。它非常适合在 IoC 容器和服务管理器的实例化例程期间用于“自动装配”。空接口只是告诉容器在实例化后调用特定方法,同时让依赖注入器 (DI) 通过类型提示确定要注入的参数。从技术上讲,空接口是可选的,但这是一个很好的做法,有助于防止 DI 容器调用第三方库中类似名称的方法。 (5认同)