Как я могу использовать "инъекцию зависимостей" в простых функциях php, и должен ли я беспокоиться?


Я слышу, как люди говорят о инъекции зависимости и преимуществе этого все время, но я действительно не понимаю этого.

мне интересно, является ли это решением проблемы "я постоянно передаю соединения с базой данных в качестве аргументов".

Я попытался прочитать запись Википедии на нем, но пример написан на Java, поэтому я не совсем понимаю разницу, которую он пытается прояснить. ( http://en.wikipedia.org/wiki/Dependency_injection ).

Я прочитал эту статью dependency-injection-in-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();

У кого есть хороший ресурс или просто проницательность, которая делает метод и выгоду-кристально ясными?

5 67

5 ответов:

инъекция зависимостей-это большое слово для "у меня есть еще несколько параметров в моем конструкторе".

Это то, что вы делали до ужасной волны Синглтона, когда вам не нравились глобалы :

<?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

ваш первый пример и инъекция зависимости, вы вводите зависимость от объекта базы данных в функцию.

Сара сказала, что это не так, но ИМО это так, я считаю, что она думает о контейнерах для инъекций зависимостей, которые находятся на следующем уровне:

http://components.symfony-project.org/dependency-injection/trunk/book/02-Dependency-Injection-Containers

ни один из ваших примеров не похож на инъекцию зависимостей, хотя версия one является самой близкой. Инъекция зависимостей-это метод, используемый в объектно-ориентированном программировании, где конструктор объекта имеет аргументы для объектов службы, которые ему нужны, и эти объекты Службы передаются создателем экземпляра (который может быть фабрикой, тестом или платформой инъекции зависимостей).

чтобы обойти проблему "всегда передавать объект подключения", вы можете захотеть рассмотрим шаблон шаблон. Шаблон шаблона в основном является абстрактным базовым классом с общей частью повторяющегося блока кода и абстрактными методами, позволяющими варьировать экземпляры этих повторяющихся блоков кода. В основном база представляет собой шаблон блока кода, а абстрактные методы-это пробелы, которые необходимо заполнить. Я лично использую шаблон метода шаблона для управления ресурсами базы данных на Java.

Я сам много искал по этой теме (PHP Dependency Injection) и не нашел много по своему вкусу. Много было написано на эту тему для других языков (Google Guice -http://code.google.com/p/google-guice/; Java Spring), но я не мог найти много доступных для PHP. Однако, независимо от языка, проблемы схожи.

три версии, которые вы перечисляете в своем вопросе, являются типичным подходом. Версия 3 является наиболее близкой к направление, в котором я видел развитие отрасли. Перекладывая ответственность за создание зависимых объектов за пределами класса, вы можете манипулировать ими по своему усмотрению в тестовом коде. Однако проблема, с которой я столкнулся при таком подходе, заключается в том, что вы получаете длинные цепочки зависимых объектов в своем конструкторе, которые потенциально не могут даже использоваться получающим объектом, но передаются вторичному зависимому объекту. Это становится грязным, и вы теряете знания о том, что приходит откуда.

пример контейнера зависимостей от @Arkh и @mmmshuddup-отличное начало, но я тем не менее нашел ограничения и с этим подходом. Окончательное решение, на котором я прибыл, было изготовленным на заказ решением, смоделированным несколько после шаблона торта, популярного в Scala. Это позволяет передать одну зависимость в каждый из ваших конструкторов, и это позволяет определить конструкцию по умолчанию зависимых объектов на класса. Это освобождает вы из длинных цепочек зависимостей, а также теряете контроль над реализацией ваших зависимостей по умолчанию.

Я назвал систему дизельной, и я был очень доволен ею. Я выложил код на GitHub для всех желающих. Вы можете добраться до него из блога, который я написал на эту тему, в котором описывается основное использование, а также более подробно рассматривается ваш вопрос. http://developers.blog.box.com/2012/02/15/introducting-diesel-php-dependency-injection/

инъекция зависимостей-это идея удаления зависимости между двумя компонентами, чтобы сосредоточиться на том, почему они зависят.

представьте, что у вас есть компонент A, который должен использовать услуги другого компонента B.

Если вы жестко закодируете существование B внутри A, то вы застрянете, когда захотите использовать службы sames, но реализованные другим компонентом.

поэтому обычно вы определяете интерфейс службы, который B и C будут реализовывать, и вы убедитесь, что при использовании A вы загружаете его объектами, совместимыми с необходимым интерфейсом.

в вашем случае вы можете считать, что ваш интерфейс-это сервис, на котором вы можете сделать запрос.

ваш первый случай-это тот, который ближе к идее инъекции зависимостей.