Ответ 1
Проще говоря (потому что это не проблема, ограниченная только для мира ООП), зависимость - это ситуация, когда компоненту A требуется (зависит от) компонент B, чтобы делать то, что он должен был делать. Это слово также используется для описания зависимого компонента в этом сценарии. Чтобы поместить это в ООП /PHP, рассмотрите следующий пример с обязательной аналогией автомобилей:
class Car {
public function start() {
$engine = new Engine();
$engine->vroom();
}
}
Car
зависит от Engine
. Engine
является зависимостью Car
. Этот фрагмент кода довольно плохой, потому что:
- зависимость неявная; вы не знаете этого там, пока не проверите код
Car
- классы тесно связаны; вы не можете заменить
Engine
наMockEngine
для целей тестирования илиTurboEngine
, который расширяет исходный текст без измененияCar
. - Кажется, глупо для автомобиля, чтобы он мог построить двигатель для себя, не так ли?
Включение зависимостей - это способ решения всех этих проблем, поскольку тот факт, что Car
нуждается в явном выражении Engine
и явно предоставляет ему один:
class Car {
protected $engine;
public function __construct(Engine $engine) {
$this->engine = $engine;
}
public function start() {
$this->engine->vroom();
}
}
$engine = new SuperDuperTurboEnginePlus(); // a subclass of Engine
$car = new Car($engine);
Вышеприведенный пример встраивания конструктора, в котором зависимая (объект-зависимый) предоставляется зависимому (потребителю) через конструктор класса. Другой способ - выдать метод setEngine
в классе Car
и использовать его для ввода экземпляра Engine
. Это называется инъекцией установщика и полезно в основном для зависимостей, которые должны быть заменены во время выполнения.
Любой нетривиальный проект состоит из кучи взаимозависимых компонентов, и становится легко потерять следы от того, что вводится там довольно быстро. Контейнер для инъекций - это объект, который знает, как создавать и настраивать другие объекты, знает, какова их связь с другими объектами в проекте, и делает инъекцию зависимостей для вас. Это позволяет централизовать управление всеми вашими зависимостями проекта (inter) и, что более важно, позволяет изменять/издеваться над одним или несколькими из них без необходимости редактировать кучу мест в вашем коде.
Пусть сравнивает аналогию с автомобилем и смотрит на то, что OP пытается достичь в качестве примера. Скажем, мы имеем объект Database
в зависимости от объекта mysqli
. Предположим, мы хотим использовать действительно примитивный контейнер контейнера индексов зависимости DIC
, который предоставляет два метода: register($name, $callback)
, чтобы зарегистрировать способ создания объекта под заданным именем и resolve($name)
, чтобы получить объект от этого имени. Наша настройка контейнера будет выглядеть примерно так:
$dic = new DIC();
$dic->register('mysqli', function() {
return new mysqli('somehost','username','password');
});
$dic->register('database', function() use($dic) {
return new Database($dic->resolve('mysqli'));
});
Обратите внимание, что мы говорим нашему контейнеру, чтобы захватить экземпляр mysqli
из себя, чтобы собрать экземпляр Database
. Затем, чтобы получить экземпляр Database
с его автоматической вставкой, мы просто:
$database = $dic->resolve('database');
Это суть этого. Несколько более сложный, но все же относительно простой и легкий для понимания контейнер PHP DI/IoC - Pimple. Подробнее см. Его документацию.
Что касается кода OP и вопросов:
- Не используйте статический класс или синглтон для вашего контейнера (или для чего-нибудь еще, если на то пошло); они оба злы. Проверьте Пимл вместо.
- Определите, хотите ли вы, чтобы ваш класс
mysqliWrapper
расширялmysql
или зависел от него. - Вызывая
IoC
изmysqliWrapper
, вы меняете одну зависимость для другой. Ваши объекты не должны знать или использовать контейнер; в противном случае это не DIC больше, чем шаблон Service Locator (анти). - Вам не нужно
require
файл класса, прежде чем регистрировать его в контейнере, так как вы не знаете, собираетесь ли вы вообще использовать объект этого класса. Сделайте все настройки вашего контейнера в одном месте. Если вы не используете автозагрузчик, вы можетеrequire
войти в анонимную функцию, зарегистрированную в контейнере.
Дополнительные ресурсы:
- Инверсия контрольных контейнеров и шаблон внедрения зависимостей от Martin Fowler
- Не смотрите на вещи - Чистый код Разговор о IoC/DI