Подтвердить что ты не робот

Зависимость-инъекция в реальной жизни

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

Я нашел Bucket в Github и некоторое время обманывал его, чтобы понять основы. То, что я не могу придумать, - это когда нужно создать контейнер?

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

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

Скажем, что у меня будет следующий код:

$session_container = new bucket_Container();
$session_container->create('Database');
$session_container->create('Database_Sessions');

$log_container = new bucket_Container();
$log_container->create('Database');
$log_container->create('Database_Log');

Итак, здесь у нас есть два контейнера или в этом случае ведра для двух совершенно разных применений, которые взаимно зависят от их класса Database.

Моя логика говорит мне, что приведенный выше код создаст два независимых экземпляра класса Database, что означает, что мне все равно придется сделать Database -class singleton, чтобы убедиться, что параллельные экземпляры моего подключения к базе данных не являются 't встречается?

Правильно ли это?

4b9b3361

Ответ 1

Я не знаю много о конкретной lib, но предполагая, что он позволяет использовать factory, пусть factory возвращает тот же экземпляр.

Изменить: Хорошо, это просто на индексной странице Bucket GitHub.

class MyFactory {
  function new_PDO($container) {
    return new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
  }
}

$bucket = new bucket_Container(new MyFactory());
$db = $bucket->get('pdo');

Итак, в вашем случае вы можете просто сделать:

class MyFactory {
   private $pdo;
   function new_Database($container) {
     if($this->pdo){
         return $this->pdo;
     }
     return $this->pdo = new PDO("mysql:host=localhost;dbname=addressbook", "root", "secret");
   }
}
$factory = new MyFactory();

$session_container = new bucket_Container($factory);
$session_container->create('Database_Sessions');

$log_container = new bucket_Container($factory);
$log_container->create('Database_Log');

Что-то вроде этого. Не похоже на ракетную науку.

Edit2: у меня недостаточно комментариев, чтобы прокомментировать вопрос (немного глупо), но в ответ на вашу "модульность": подумайте о контейнере как о "клеве" вашего приложения. Действительно, если у вас большое приложение, вы можете захотеть "приклеить" только в изолированной части вашего приложения. Это допустимая проблема инкапсуляции. Но даже тогда вам все еще нужен контейнер, который обрабатывает инъекцию на самом высоком уровне абстракции. Если вы просто создаете отдельный контейнер для каждой части вашего приложения, вы либо получаете ненужное дублирование экземпляров, либо вам нужно применить другой уровень управления экземплярами, который никак не улучшает инкапсуляцию: вы все еще обмена экземплярами между различными частями вашего приложения.

Мой совет: использовать один контейнер на уровне начальной загрузки. Если вы хотите добавить инкапсуляцию для определенных частей приложения (модулей, плагинов и т.д.), Используйте "дочерние контейнеры". Детский контейнер наследует экземпляры из родительского контейнера, но родительский контейнер ничего не знает о ребенке (насколько он заинтересован, он все еще холостяк;)). Может быть, Bucket поддерживает это по умолчанию, я знаю, что другие контейнеры DI. Если нет, это очень легко реализовать с помощью Decorator. Представьте себе что-то вроде этого:

class MyContainerType extends bucket_Container {

    private $_parent;
    private $_subject;

    public function  __construct($factory = null, bucket_Container $parent = null){
        $this->_parent = $parent;
        $this->_subject = new bucket_Container($factory);
    }

    public function get($key){
        $value = $this->_subject->get($key);
        if($value){
            return $value;
        }
        return $this->_parent->get($key);
    }
    /**
     * Override and delegation of all other methods
     */
}

Ответ 2

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

Напротив. Это именно то, что вы сделали бы с контейнером di. Контейнер будет только создавать объекты по требованию, поэтому на самом деле нет никаких накладных расходов для управления всеми вами одноэлементными классами через него.

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

Ответ 3

Если вас беспокоит несколько одновременных подключений, вы можете просто использовать mysql_pconnect() или эквивалент для используемой базы данных. Он будет проверять, открыто ли соединение и использовать существующее соединение, если оно есть.

Что касается проблемы с контейнером, я видел, как это было сделано двумя способами, о которых вы, похоже, знаете оба. Первый способ состоит в том, чтобы инфраструктура считывала вашу схему базы данных и создавала классы для каждой таблицы. Мне лично это не нравится. Symfony - это одна структура, которая делает это (используя доктрину ORM).

Более предпочтительный метод, который я видел, это иметь общий контейнер, который в основном создает sql для вас, учитывая таблицу, столбцы и действие. Это подход, применяемый codeIgniter:

$query = $this->db->get('mytable');
$query = $this->db->get_where('mytable', array('id' => $id), $limit, $offset);