ОБНОВЛЕНИЕ ОБЩЕСТВЕННОГО ОБСЛУЖИВАНИЯ:
Я многому научился с тех пор, как изначально задал этот вопрос.Если вы читаете это, пожалуйста, примите мой совет и вообще избегайте static
.Просто.Не.Используйте.Это. Нет способа внедрения зависимостей;путь внедрения зависимостей.
Недавно я потратил много времени на изучение различных концепций инверсии управления ( IOC ).Я полностью согласен с теми, кто считает Service Locator антипаттерном.Я построил один, чтобы повозиться с ним, и был ошеломлен мощью, которую он позволял импортировать «глобальные» сущности в середине классов, используя статические методы локатора, а также возможность скрывать фактические зависимости объекта.
Перемещениена основе сервисного локатора я решил создать контейнер внедрения зависимостей ( DI ), который дал мне гибкость доступа к статическим зависимостям без сопутствующих недостатков статических переменных.
Вот простой примертакой реализации:
<?php
class Container
{
protected static $params = [];
public function store($key, $val)
{
static::$params[$key] = $val;
return $this;
}
public function fetch($key)
{
if (isset(static::$params[$key])) {
return static::$params[$key];
}
$msg = "No parameter match found in container: $key";
throw new OutOfBoundsException($msg);
}
}
$container = new Container;
$container->store('widgetDep', new WidgetDependency);
$container->store('kumquatDep', new KumquatDependency);
// and somewhere else in the application without access to the global namespace
// (i.e. the $container instance we just created) ...
$widget = new Widget(new Container);
$kumquat = new Kumquat(new Container);
Это кажется шагом в правильном направлении, потому что статическое свойство $params
защищено, и нет статических методов для доступа или манипулирования им в «глобальной» статической области:объект требует доступа к контейнеру для доступа к зависимостям.
Ой, подождите ...
К сожалению, хранение зависимостей в этом контейнере означает, что теперь каждый объект с внедрением зависимостей имеет поддельноезависимость от объекта контейнера, таким образом скрывая его real зависимости. Еще один негативный побочный эффект состоит в том, что каждому объекту будет предоставлен доступ ко всем доступным зависимостям в контейнере, и, очевидно, объект Widget не должен иметь доступа к * 1035.* Kumquat Зависимости объекта.Кроме того, использование абстрактной фабрики с таким подходом делает только перемещение фиктивной зависимости из классов Widget и Kumquat в фабрику.
Альтернатива PHP 5.4
Благодаря новым возможностям разыменования конструкции объекта 5.4 мы могли бы сделать что-то вроде следующего без необходимости доступа к уже созданному экземпляру $container
, который существует в глобальном пространстве имен:
$widget = new Widget((new Container)->fetch('widgetDep'));
$kumquat = new Kumquat((new Container)->fetch('kumquatDep'));
Используя этот подход, мы успешно:
- Устранили зависимость контейнера от объектов Widget и Kumquat, позволяя их конструкторам указывать конкретные объекты зависимости, которые им требуются;
- Предотвращение нижестоящего Widgetи объекты Kumquat, имеющие доступ к зависимостям, о которых они не должны знать, существуют;
- Сохранены возможности хранения статических зависимостей.
Теперь возможный недостаток заключается в том, что этот подход означает, что разработчик должен быть дисциплинированнымдостаточно, чтобы не передать полный Container
объект в качестве зависимостиndency.Это очень важно.
Итак, вопрос ...
В двух частях:
- Какие конкретные недостатки вы видите при таком подходе, и
- Статический
Container::$params
вообще необходим?Должно ли оно вместо этого быть стандартным защищенным свойством, доступ к которому производят классы / методы фабрики графов top-of-the-object-графа в глобальном пространстве имен в любом случае (устраняя необходимость в static
)?