Прочитай определение DI. То, что у тебя в этом примере - это не DI, а Service Locator (многие считают антипатитерном).
В DI у тебя все типы и так будут описаны.
по той же самой ссылочке
http://www.martinfowler.com/articles/injection.html есть и определение service locator и даже отдельная часть service locator vs di
я просто про цитирую
The fundamental choice is between Service Locator and Dependency Injection. The first point is that both implementations provide the fundamental decoupling that's missing in the naive example - in both cases application code is independent of the concrete implementation of the service interface. The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.
опять же это если придерживаться мнения Фаулера, если в вашем понимание какие то свои di и service locator то ничего страшного покажите ссылку куда вы ссылаетесь, а если придумали статью то расскажите об этом людям и опять же ссылку туда
в примерах выше классы зависимостей (application class в формулировке Фаулера) (Session и SessionStorage) напрямую не обращаются к $container или $app а эти классы разрешают зависимость через анонимную функцию и проставляют зависимости в application class
Вот популярный пример service locator
http://api.symfony.com/2.7/Symfony/Component/DependencyInjection/ContainerAware.html который как ты верно заметил может считаться анти паттерном, с точки зрения некоторых людей.
объясню довольно популярный пример (если можно в терминах Java spring)
предположим есть interface (I) и в проекте есть 2 его реализации (A, B)
и есть другой класс(C) который зависит от этого интерфейса (пусть constructor injection, или method injection, или property injection не важно)
и по началу вы используете C и в зависимости вы передаете то что указано в разрешение I (например экземпляр класса A)
через некоторое время появляется класс D который ожидает I но ему надо реализацию в виде B (например A хранит данные в memcache, а тут надо хранить в mongo или redis интерфейсы могут быть одинаковы а хранение разное)
такую проблему в spring решают с помощью именованных бинов (named bean)
но там это возможно так есть этап компиляции и чтение анотаций и дерево зависимостей строиться во время компиляции и объкеты создаются только те которые необходимо.
теперь вернемся в php
что мешает имя контейнера давать как I.class ? а получение объекта сделать с помошью анонимной функции это не service locator
не нравиться анонимная функция(которая выглядит красивей и понятней) сделайте свой ComponentImplementation
PHP:
class ComponentImplementation implement ContainerInterface {
public function __constructor(Locator $locator, array $constructInjections = [], array $methodInjections = []) {
$this->setLocator($locator);
$this->constrcutInject($constructInjections);
// и так далее
}
public function setLocator(Locator $locator) {
}
public function constructorInject(array $containers) {
}
public function methodInjection(array $containers) {
}
public function resolve() {
// тут создаем объект с аргументами в конструкторе и вызываем методы и прочие штуки
}
}
я код накидал примерный класс для создания своего контейнера(его можно сделать и красивей например убрать locator из конструктора и тд) теперь как использовать из примера выше (первую ситуацию без named bean, причем именовать придется оба bean, A и B иначе все сломается)
PHP:
$locator[A.class] = new ComponentImplementation($locator);
$locator[B.class] = new ComponentImplementation($locator);
$locator[I.class] = $locator['A.class']; // когда понадобиться можно например присвоить B.class
$locator[C.class] = new ComponentImplementation($locator, [I.class]);
$locator[D.class] = new ComponentImplementation($locator, [B.class]);
собственно теперь управление выбором имплементации лежит в 3 строке
можно все это сделать изящней и красивей используя анотации и так далее но я не считаю анотации в php хорошей штукой.
а плюс ко всему в моей реализации можно сделать подгрузку определений динамической (частями) и довольно просто создали новый контейнер(хотя его не обязательно было делать анонимная функция гораздо более гибкий инструмент), а теперь как тоже самое сделать в pimple без overwride method ?
это очень черновой вариант и тут можно много к чему прикопаться и сделать лучше, собственно если будет потребность в такой штуке(вроде ComponentImplementation) можно зависти задачу на github и описать что примерно охото (с примерами) я в свободное время сяду и возможно реализую это, ну или можно самому и pull request (но это очень мало вероятный сценарий но я был бы искренне рад).
блин выглядит так будто я написал что что должно быть лучше всех и всего и универсально подходить ко всему, но это не так и это не возможно, я лишь написал довольно удобный и самое главное гибкий инструмент который можно использовать в своём проекте так как это вам надо, да мало примеров и best практик, да в документации много много ошибок в русском языке, да возможно что то существует и лучше (но я пока не знаю я уверен и в других библиотеках можно много чего интерсеного сделать), но в этой библиотеке основная возможность это создание своих контейнеров(ContainerInterface) и динамическая загрузка из любова удобного вам формата (LoaderInterafce) и это я сделал довольно не плохо, да её могут использовать как Service Locator или даже как Registor
я рад что вы задаете вопросы и ищите недостатки в примерах и даже указывате на них