Как я могу использовать «Dependency Injection» в простых функциях php, и стоит ли мне беспокоиться?

php dependency-injection parameter-passing

26837 просмотра

5 ответа

15968 Репутация автора

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

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

Я попытался прочитать статью в Википедии, но пример написан на 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();

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

Автор: Kzqai Источник Размещён: 12.02.2010 11:22

Ответы (5)


7 плюса

253 Репутация автора

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

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

Автор: Sarah Happy Размещён: 13.02.2010 12:19

13 плюса

5452 Репутация автора

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

Сара сказала, что это не так, но, по-моему, так и есть, я думаю, она думает о контейнерах внедрения зависимостей, которые находятся на следующем уровне:

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

Автор: jmoz Размещён: 31.03.2010 02:19

75 плюса

7920 Репутация автора

Решение

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

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

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

Автор: Arkh Размещён: 31.03.2010 02:48

2 плюса

1359 Репутация автора

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

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

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

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

Автор: Ben Размещён: 02.04.2012 06:59

2 плюса

16112 Репутация автора

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

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

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

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

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

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

Автор: Jerome WAGNER Размещён: 07.06.2012 10:45
Вопросы из категории :
32x32