Я слышу, как люди говорят об инъекции зависимостей, и все это приносит пользу, но я этого не понимаю.
Мне интересно, является ли это решением проблемы «Я передаю соединение с базами данных как аргументы все время».
Я пробовал читать запись на wikipedia, но пример написан на Java, поэтому я не понимаю, в чем разница, которую он пытается прояснить. ( http://en.wikipedia.org/wiki/Dependency_injection ).
Я прочитал эту статью, связанную с зависимостью-в-php ( http://www.potstuck.com/2009/01/08/php-dependency-injection/ ), и, похоже, цель состоит в том, чтобы не передавать зависимости к объекту напрямую, но оцеплять создание объекта вместе с созданием его зависимостей. Однако я не уверен, как применить это в контексте использования php-функций.
Кроме того, это следующая инъекция зависимостей, и я должен попытаться сделать инъекцию зависимостей в функциональном контексте?
Версия 1: (тип кода, который я создаю, но не люблю, каждый день)
function get_data_from_database($database_connection){ $data = $database_connection->query('blah'); return $data; }
Версия 2: (не нужно пропускать соединение с базой данных, но, возможно, не использовать инъекцию зависимостей?)
function get_database_connection(){ static $db_connection; if($db_connection){ return $db_connection; } else { // create db_connection ... } } function get_data_from_database(){ $conn = get_database_connection(); $data = $conn->query('blah'); return $data; } $data = get_data_from_database();
Версия 3: (создание «объекта» / данных является отдельным, а код базы данных по-прежнему, поэтому, возможно, это будет считаться инъекцией зависимостей?)
function factory_of_data_set(){ static $db_connection; $data_set = null; $db_connection = get_database_connection(); $data_set = $db_connection->query('blah'); return $data_set; } $data = factory_of_data_set();
У кого-нибудь есть хороший ресурс или просто проницательность, которая делает метод и преимущества -кристальными?
Инъекционная инъекция – большое слово для «У меня есть еще несколько параметров в моем конструкторе».
Это то, что вы делали перед волной синглтона, когда вам не нравились глобальные переменные:
<?php class User { private $_db; function __construct($db) { $this->_db = $db; } } $db = new Db(); $user = new User($db);
Теперь уловкой является использование одного класса для управления вашими зависимостями, что-то вроде этого:
class DependencyContainer { private _instances = array(); private _params = array(); public function __construct($params) { $this->_params = $params; } public function getDb() { if (empty($this->_instances['db']) || !is_a($this->_instances['db'], 'PDO') ) { $this->_instances['db'] = new PDO( $this->_params['dsn'], $this->_params['dbUser'], $this->_params['dbPwd'] ); } return $this->_instances['db']; } } class User { private $_db; public function __construct(DependencyContainer $di) { $this->_db = $di->getDb(); } } $dependencies = new DependencyContainer($someParams); $user = new User($dependencies);
Вы должны думать, что вы просто еще один класс и сложнее. Но вашему пользовательскому классу может понадобиться что-то, чтобы регистрировать сообщения, такие как много других классов. Просто добавьте функцию getMessageHandler в свой контейнер зависимостей, а некоторые $this->_messages = $di->getMessageHandler()
в ваш пользовательский класс. Ничего не изменится в остальной части вашего кода.
Вы получите много информации о доске symfony
Ваш первый пример инъекции зависимостей ИИ, вы вставляете зависимость от объекта базы данных в функцию.
Сара сказала, что это не так, но, я думаю, она думает о контейнерах для инъекций зависимых, которые являются следующим уровнем:
Ни один из ваших примеров не выглядит как инъекция зависимостей, хотя первая версия наиболее близка. Инъекция зависимостей – это метод, используемый в объектно-ориентированном программировании, где конструктор объекта имеет аргументы для необходимых ему объектов службы, а те служебные объекты передаются создателем экземпляра (который может быть фабрикой, тестом или структура внедрения инъекций).
Чтобы обойти проблему «всегда передавать объект соединения», вы можете рассмотреть шаблон шаблона. Шаблон шаблона в основном представляет собой абстрактный базовый класс с общей частью повторяющегося блока кода и абстрактные методы, позволяющие варьировать между экземплярами этих повторяющихся кодовых блоков. В основном база является шаблоном блока кода, а абстрактные методы – это заполняемые пробелы. Я лично использую шаблон шаблона метода для управления ресурсами базы данных в Java.
Я сделал большой поиск по этой теме (PHP Dependency Injection) и не нашел много по своему вкусу. Многое было написано на эту тему для других языков (Google Guice – http://code.google.com/p/google-guice/ ; Java Spring), но я не смог найти много доступного для PHP. Однако, независимо от языка, проблемы схожи.
Типичный подход – три версии, которые вы перечисляете в своем вопросе. Версия 3 ближе всего к тому направлению, в котором я видел отрасль. Переходя ответственность за создание зависимых объектов вне вашего класса, вы можете манипулировать ими, как вам будет угодно, в вашем тестовом коде. Тем не менее, проблема, с которой я столкнулся с этим подходом, заключается в том, что у вас заканчиваются длинные цепочки зависимых объектов в вашем конструкторе, которые потенциально даже не могут быть использованы получающим объектом, но передаются второму зависимому объекту. Это становится беспорядочным, и вы теряете знание того, что происходит оттуда.
Пример Container Dependency от @Arkh и @mmmshuddup – отличное начало, но я тем не менее нашел ограничения и с этим подходом. Окончательным решением, по которому я приехал, было заказное построенное решение, смоделированное несколько после того, как популярный в Scala шаблон Cake. Он позволяет передавать одну зависимость в каждый из ваших конструкторов. И она позволяет определить конструкцию по умолчанию для зависимых объектов для каждого класса. Это освобождает вас от длинных цепочек зависимостей, а также теряет контроль над реалиями ваших зависимостей по умолчанию.
Я назвал систему Diesel, и я был очень доволен ею. Я опубликовал код для github для всех, кого это интересует. Вы можете перейти к нему из блога, который я написал по этому вопросу, в котором описывается основное использование, а также более подробно изложено в вашем вопросе. http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/
Инъекция зависимостей – это идея устранения зависимости между двумя компонентами, чтобы сосредоточиться на том, почему они зависят.
Представьте, что у вас есть компонент A, которому необходимо использовать службы другого компонента B.
Если вы жестко указали существование B внутри A, тогда вы будете застревать, когда вы захотите, чтобы A использовал службы sames, но реализован другим компонентом.
Как правило, вы определяете интерфейс службы, который реализует B и C, и вы убедитесь, что, когда вы используете A, вы кормите его объектами, совместимыми с необходимым интерфейсом.
В вашем случае вы можете подумать, что ваш интерфейс – это служба, по которой вы можете сделать запрос.
Ваш первый случай – это тот, который ближе к идее Injection Dependency.