Мартин Фаулер круто пишет обо всех паттернах. Про DI можно почитать
тут. Вообще у него отличный блог. И он же автор книги
P of EAA. Правда русский ее перевод крайне не рекомендую читать, можно только запутаться, так что читайте в оригинале.
Если хотите разобраться с паттернами, то самая простая (и при этом дельная!) книга - это
Фриман&Фриман. Ее можно читать и на русском.
Применительно к PHP - вот лучшая книга про шаблоны (и не только), которую я видел
PHP. Объекты, шаблоны и методики программирования от Мэт Зандстра.
Порядок прочтения рекомендую следующий: Фриман&Фриман, затем Мэт Зандстра, и на десерт Фаулера P of EAA.
UPD:
Важно отличать паттерн Dependency Injection от Dependency Injection Container.
Простейший пример внедрения зависимости:
interface IEngine {}
class V8Engine implements IEngine {}
class Car {
public function __constructor(IEngine $engine) {
$this->engine = $engine;
}
}
$car = new Car(new V8Engine());
Простейший пример игнорирования явного внедрения (для такого кода трудно писать unit-тесты, его труднее понимать и править):
class V8Engine {}
class Car {
public function __constructor() {
$this->engine = new V8Engine();
}
}
$car = new Car();
Отличный (и легковесный) пример DIC - это
pimple:
// define some services
$container['session_storage'] = function ($c) {
return new SessionStorage('SESSION_ID');
};
$container['session'] = function ($c) {
return new Session($c['session_storage']);
};
Советую прочитать и понять его исходники, чтобы убедиться, что в DIC (во всяком случае для PHP) нет никакой магии. Первая версия была всего ~100 строк. Необходимо также отметить, что класс Session использует шаблон Dependency Injection, явно определяя свою зависимость от SessionStorage. А контейнер делает лишь правильную связку.
И да, контейнер сам по себе можно использовать как service locator, если к нему, например, есть глобальный доступ. Но это очень плохая практика, потому что если что-то обращается к сервис локатору, то формально оно начинает зависеть сразу от всех компонентов системы.