шаблоны проектирования — как избежать конфликтных черт PHP, используемых для внедрения зависимостей

Наконец-то я приступил к изучению черт в PHP. Первое, что я решил попробовать — это внедрение битов конфигурации в классы. Если я использую 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
}
}

Тоже отлично. Теперь проблема возникает, если эти две черты хотят использовать друг друга. Кажется вполне разумным, что в классе логгера должен быть введен объект конфигурации, что означает следующее:

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.

Я мог бы просто опустить use Config; часть от черты Logger, зная, что это будет там в конце. Но это кажется мне странным, поскольку создает некую внешнюю зависимость. Что если я захочу использовать Logger где-нибудь, у которого еще нет черты конфигурации? Это решение также означает, что мне нужно, чтобы моя IDE (PhpStorm 8) предупреждала меня о неизвестных методах и не предлагала автозаполнение. Я понимаю, что могу исправить эти проблемы по очереди, используя @method, но это, так сказать, просто нанесение помады на свинью.

Я мог бы также использовать псевдоним битов конфигурации в Logger, но это также проблематично.

Все это имеет какой-то запах, но я еще не выяснил, потому что это новый шаблон для меня или действительно вонючий шаблон. В любом случае, я не уверен, что лучший способ заставить этот подход работать на самом деле.

Любой совет, как лучше всего решить эту проблему в чертах? Или лучше избегать черт быстрого доступа к DIC?

6

Решение

Метод, который я нашел полезным, использует как методы получения, так и установки. Это тогда позволяет вам требовать, чтобы определенный геттер существовал, не вступая в конфликт с другими чертами.

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, вы получите фатальную ошибку: класс Baz содержит 1 абстрактный метод и поэтому должен быть объявлен как абстрактный или реализовать оставшиеся методы (Baz :: GetConfig)

3

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]