PHP Ленивая загрузка объектов и внедрение зависимостей

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

Проблема у меня примерно такая:Скажем, у меня есть два класса:Автомобиль и Пассажир; Для этих двух классов у меня есть несколько преобразователей данных для работы с базой данных :CarDataMapper и PassengerDataMapper

Я хочу иметь возможность делать что-то подобное в коде:

$car = CarDataMapper->getCarById(23); // returns the car object
foreach($car->getPassengers() as $passenger){ // returns all passengers of that car
    $passenger->doSomething();
}

Прежде чем я узнал что-либо о DI, я бы создал свои классы вот так:

class Car {
    private $_id;
    private $_passengers = null;

    public function getPassengers(){
        if($this->_passengers === null){
            $passengerDataMapper = new PassengerDataMapper;
            $passengers = $passengerDataMapper->getPassengersByCarId($this->getId());
            $this->setPassengers($passengers);
        }
        return $this->_passengers;  
    }

}

У меня также был бы аналогичный код в методе Passenger->getCar()для получения автомобиля, в котором находится пассажир.

Теперь я понимаю, что это создает зависимости (ну, я понял это раньше тоже, но я не знал, что это "неправильно")между объектами Car и Passenger и объектами преобразователя данных.

При попытке придумать решение для этого пришло на ум два варианта, но мне не очень нравится ни один из них:

1:Делать что-то вроде этого:

$car = $carDataMapper->getCarById(23);
$passengers = $passengerDataMapper->getPassengersByCarId($car->getId());
$car->setPassengers($passengers);

foreach($car->getPassengers() as $passenger){
    $passenger->doSomething();
}

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

2:Внедрение картографов данных в объекты автомобиля и пассажира и наличие чего-то подобного:

class Car {
    private $_id;
    private $_passengers = null;
    private $_dataMapper = null;

    public function __construct($dataMapper){
        $this->setDataMapper($dataMapper);
    }

    public function getPassengers(){
        if($this->_passengers === null && $this->_dataMapper instanceof PassengerDataMapper){
            $passengers = $this->_dataMapper->getPassengersByCarId($this->getId());
            $this->setPassengers($passengers);
        }
        return $this->_passengers;  
    }
}

Мне это не нравится больше, потому что не похоже, что Автомобиль действительно не знает о преобразователе данных, и без данных маппер, Автомобиль мог вести себя непредсказуемо (не возвращая пассажиров,когда они на самом деле есть)

Итак, мой первый вопрос :Использую ли я здесь совершенно неправильный подход, потому что, чем больше я смотрю на это, тем больше кажется, что я создаю ORM, а не бизнес-уровень?

Второй вопрос:Есть ли способ фактически отделить объекты и преобразователи данных таким образом, чтобы я мог использовать объекты, как описано в самом первом блоке кода?

Третий вопрос:Я видел некоторые ответы для других языков (некоторой версии C, я думаю)решение этой проблемы с чем-то вроде этого, описанного здесь: Как правильно внедрить зависимость доступа к данным для отложенной загрузки? Поскольку у меня не было времени поиграться с другими языками, для меня это не имеет смысла, поэтому я был бы признателен, если бы кто-нибудь объяснил примеры по ссылке на PHP-ish.

Я также просмотрел некоторые DI-фреймворки и прочитал о DI-контейнерах и инверсии управления, но насколько я понял, они используются для определения и внедрения зависимостей для «нединамических» классов, где, например, Car будет зависеть на двигателе, но для этого не потребуется динамическая загрузка движка из базы данных, он будет просто создан и введен в автомобиль.

Извините за длинное сообщение и заранее спасибо.

18
задан Community 23 May 2017 в 12:32
поделиться