а если инстанс типо фасад типо модуль создать один раз и линковать его везде где его используешь один раз это будет очень страшно?1. не надо было создавать инстанс
но тогда нельзя будет динамически настраивать набор модулей приложенияа если создать не в глобальной области, а в некоемом методе, даже если при инициализации зависимостей рабочего модуля, или лучше при появлении события когда инициализация зависимости необходима?
здесь зависит от логики модуля, некоторые требуют создания отдельного инстанса под каждый набор параметров,Модуль не должно волновать, сколько там где инстансов чего будет, это вопрос приложения. А на уровне приложения и так уже есть какой-то способ управления зависимостями.
<?php
trait SingleInstanceModule
{
protected static $inst = [];
/**
*
* @return static
*/
public static function facade(array $dependencies = [])
{
if ( ! isset(static::$inst[static])) {
static::$inst[static] = new static($dependencies)
}
return static::$inst[static];
}
protected function __construct(array $dependencies = [])
{
foreach ($dependencies as $k => $v) {
if (property_exists($this, $k)) {
$this->{$k} = $v;
}
}
На уровне его реализации - нетздесь зависит от логики модуля
для этого существуют фабрикинекоторые требуют создания отдельного инстанса под каждый набор параметров
что значит "надо?" Надо может быть конкретному приложению. Если какой-то модуль спроектирован так, что нельзя использовать одновременно несколько инстансов (например, использует глобальные переменные для передачи или сохранения состояния), ему место на помойке.некоторые надо использовать как синглтон
Не нужно додумывать за пользователей класса. Это всегда приводит к плохому дизайну. Сегодня оправданием сингельтона может служить только одно: это обертка легаси кода, когда создание двух экземпляров _гарантировано_ приведет к программному сбою. Например, обертки старых dll библиотек, которые имеют только один сегмент данных на процесс и кривой дизайн, не позволяющий связывать функционал с объектами. Или использование устаревших технологий типа DDE, которые ограничены одним сервером на процесс и когда последовательный вызов этих функций для двух разных серверов приведет к несогласованному состоянию. Во всех остальных случаях за использование сингельтонов нужно отрывать руки. В 99.999% случаев сингельтоны это просто способ обхода DI со всеми вытекающими.Если не может возникнуть нужды в двух инстансах в рамках одного процесса, то разработчику модуля логично будет запретить его неограниченное инстанцирование, чтобы,например, при использовании его другими разработчиками, избежать излишнего потребления памяти или параллельной обработки одних и тех же данных (плюс блокировки в этом случае).
в этом случае только синглтоны не помогутИли использование устаревших технологий типа DDE, которые ограничены одним сервером на процесс и когда последовательный вызов этих функций для двух разных серверов приведет к несогласованному состоянию
DI какую задачу решает? Decoupling. То бишь понижение связанности за счет реализации взаимодействия на базе абстракций. Статика убивает наследование и полиморфизм. Ты уже не можешь оперировать абстракцией, потому что для доступа через статический метод нужно идентифицировать реализацию. Трейты вроде как не убивают наследование, но это другой продвинутый способ стрельнуть себе в ногу. В общем, твой вариант 1) повышает связанность кода 2) ограничивает область применения класса одним экземпляром. Ты передачей зависимостей пытаешься снизить связанность, а статическим акцессором тут же ее добавляшь. Ну вроде как сам себе по морде дал. При чем абсолютно ни за что.а что с обходом DI?
если честно, я просто не могу понять реальных проблем которых дает такое решение,2) ограничивает область применения класса одним экземпляром
<?php
interface DIPuttable
{
public function getDIKey();
public function getInstanceFromDI();
}
class TargetClass implements DIPuttable
{
public static function getDIKey()
{
return 'targetClass';
}
/**
* @return static
*/
public static function getInstanceFromDI()
{
if (null === ($i = \DIContainer::get(self::getDIKey)) {
throw new \Exception('Seems class hasnt been initiated yet');
}
return $i;
}
public function __construct()
{
$this->dep1 = \DIContainer::get(OtherClass1::getDIKey());
$this->dep2 = \DIContainer::get(OtherClass2::getDIKey());
}
}
// ..... somewhere during bootstraping
$tClass = new TargetClass();
DIContainer::set($tClass->getDIKey(), $tClass);