我终于可以探索PHP的特性了。我以为我会尝试的第一个地方是将配置位注入(inject)到类中。如果我使用的是DIC,则在任何需要配置对象的类中都可能有这样的代码:

protected function SetConfig($config) {
    $this->config = $config;
}

protected $config;

这似乎很自然地适合于特质,以避免到处都有该样板代码,因此我可以创建以下代码:
trait Config {
    protected function SetConfig($config) {
        $this->config = $config;
    }

    protected $config;
}

然后像这样使用它:
class Foo {
    use Config;

    public function __construct() {
        //can now use $this->config
    }
}

那太棒了。现在让我们说我想创建另一个特征,例如,用于记录:
trait Logger {
    protected function SetLogger($logger) {
        $this->logger = $logger;
    }

    protected $logger;
}

我可以这样使用:
class Foo {
    use Logger;

    public function __construct() {
        //can now use $this->logger
    }
}

也很棒现在,如果这两个特征想互相使用,问题就来了。记录器类需要注入(inject)配置对象似乎很合理,这意味着可以这样做:
trait Logger {
    use Config;

    protected function SetLogger($logger) {
        $this->logger = $logger;
    }

    protected $logger;
}

但是,当另一个类同时使用这两个特征时,事情就会破裂:
class Foo {
    use Config, Logger;

    public function __construct() {
        //want to use $this->config and $this->logger
    }
}

当然,这是行不通的,因为在Foo中有效地复制了配置位。

我可以忽略Logger特性中的use Config;片段,因为它知道最后会出现。但这对我来说很奇怪,因为它产生了某种外部依赖性。如果我想在尚未具有config特性的地方使用Logger怎么办?该解决方案还意味着我需要承受IDE(PhpStorm 8)的警告,告知我未知方法,并且不提供自动补全功能。我意识到我可以使用@method依次解决这些问题,但这可以说是在 pig 身上涂上了口红。

我也可以在Logger中为配置位取别名,但这也是有问题的。

所有这些都有一点气味,但是我还没有弄清楚这是否是因为这对我来说是一种新模式,还是真的是一种臭气熏天的模式。无论哪种方式,我都不确定使这种方法真正起作用的最佳方法。

对解决特质问题的最佳方法有何建议?还是更好地避免DIC快捷方式的特征?

最佳答案

我发现有用的方法是使用getter和setter。然后,这使您可以要求存在特定的 setter/getter ,而不会与其他特征冲突。

trait Config {
    protected function SetConfig($config) {
        $this->config = $config;
    }

    protected function GetConfig() {
        return $this->config;
    }

    protected $config;
}

trait Logger {
    abstract protected function GetConfig();

    protected function SetLogger($logger) {
        $this->logger = $logger;
    }

    protected $logger;
}

class Baz {
    use Config, Logger;

    // ...

}

在Baz中,Config特性提供了所需的抽象方法,并且Baz的编写没有错误。如果错误地仅使用Logger,则会出现致命错误:Class Baz包含1个抽象方法,因此必须声明为abstract或实现其余方法(Baz::GetConfig)

10-04 23:21