frolover
@frolover

Класс управления зависимостями, как вам реализация?

Набросал класс управления зависимостями в приложении

/**
 * Class DependencyManager
 */
class DependencyManager {

    /**
     * @var array of dependencies
     */
    public $dependencies;

    /**
     * DependencyManager constructor
     */
    public function __construct() {

        $this->dependencies = [

          [
              'class' => 'SomeClass',
              'dependencies' => [
                  'DependentedClass', 'SecondDependentedClass'
              ]
          ]

        ];

    }

    /**
     * @param $class
     * @return null OR Dependencies of class
     */
    public function checkDependencies($class) {

        $dependenciesByClass = null;

        foreach( $this->dependencies as $data ) {

            if($data['class'] === $class) {

                $dependenciesByClass = $data['dependencies'];
                break;
            }

        }

        return $dependenciesByClass;

    }

}

/**
 * Class DependentedClass
 */
class DependentedClass {

    public $variable = 'this text placed in DependentedClass <br />';

}

/**
 * Class SecondDependentedClass
 */
class SecondDependentedClass {

    public $moreVariable = 'this text placed in SecondDependentedClass';

}

/**
 * Class SomeClass
 * class for example
 * It is dependent on other classes
 */
class SomeClass {

    public $varInDependentedClass;
    public $varInSecondDependentedClass;


    public function __construct(DependentedClass $dependentedClass, SecondDependentedClass $secondDependentedClass) {

        $this->varInDependentedClass = $dependentedClass->variable;

        $this->varInSecondDependentedClass = $secondDependentedClass->moreVariable;

    }

}

/**
 * Class Loader
 * This class creates an instance of any class
 */
class Loader {

    public $className; 

    public $dependencyManager;

    /**
     * Loader constructor.
     * @param DependencyManager $dependencyManager
     */
    public function __construct(DependencyManager $dependencyManager) {

        $this->dependencyManager = $dependencyManager;

    }

    /**
     * @return null|object
     * this method loads classes
     */
    public function loadClass() {

        $dependencies = null;
        $arrayObjects = null;
        $reflection = null;
        $instance = null;

        $this->className = 'SomeClass';

        if( !is_null($this->className) ) {

            $dependencies = $this->dependencyManager->checkDependencies($this->className);

            if( !is_null($dependencies) ) {

                for($i = 0; $i < count($dependencies); $i++) {

                    $arrayObjects[$i] = new $dependencies[$i];

                }

                $reflection = new ReflectionClass( $this->className );

                $instance = $reflection->newInstanceArgs($arrayObjects);

            } else {
                $instance = new $this->className;
            }
        }
        return $instance;
    }
}

Usage:
$loader = new Loader( new DependencyManager() );

var_dump( $loader->loadClass() );

/*
 * var_dump() results:
 * object(SomeClass)#6
 *  (2) {
 *  ["varInDependentedClass"] => string(43) "this text placed in DependentedClass"
 *  ["varInSecondDependentedClass"] => string(42) "this text placed in SecondDependentedClass"
 *  }
 */

Очень удобная вещь, теперь можно по частям тестировать приложение.

НО

Что меня смущает:
1. То что нужно вручную собирать массив зависимостей ( метод DependencyManager::__construct() );
2. Что возможно я что то упустил либо нагородил, например формирование массива объектов-зависимостей ( метод Loader::loadClass() )

UPDATE
Еще пришла идея в классы с зависимостями передавать в аргументах интерфейсы, а не объекты.

Прошу заметить что это не полностью рабочий вариант, и прошу дать совет по основной идее работы класса, а не по пропущенным проверкам и тд. Многие моменты максимально облегчены для быстрого понимания
  • Вопрос задан
  • 460 просмотров
Решения вопроса 3
Вы решили написать свой Dependency Injection Container с блекджеком и ***?
Да, прописывать зависимости руками (в конфиге) --- это норм.
Если не хотите этим заниматься, то гуглите по ключевым словам "di container autowiring"
Ответ написан
@shaqster
Symfony3 Guru
Вот же на гитхабе симфонийский DI. Внешних зависимостей нет. Зачем изобретать велосипед? Для самообразования? Лучше изучить стандартизированный проверенный инструмент, чем писать свое на коленке.
Ответ написан
index0h
@index0h
PHP, Golang. https://github.com/index0h
// Должен быть приватным
DependencyManager::$dependencies;

// Что это за хардкод?))
DependencyManager::__construct

// 1. Вы не проверяете аргументы, что будет, если я передам в $class
// например new \Exception()? А еще лучше строку "trololo"?
// 2. Нейминг - гуано, вы не проверяете зависимость, а возвращаете.
// 3. Если зависимость не найдена - будьте добры исключение.
DependencyManager::checkDependencies($class)

// Эта переменная не нужна, передавайте ее в метод
Loader::$className

// Эта переменная должна быть приватная, что будет, если туда вставить
// например строку и попытаться обработать?
Loader::$dependencyManager;

// Херня. У вас метод делает какую-то магию.
Loader::loadClass


Из SOLID вы нарушили:
* SRP - Loader выполняет И управление зависимостями и подгрузку. То что вы называете DependencyManager - это конфигурация, но ни как не менеджер зависимостей
* OCP - у вас явно открыты свойства, которые отвечают за внутреннюю логику выполнения. А то вот конфиги из вашей конфигурации зависимостей стоит возвращать через геттер
* ISP - вы в принципе не заморачиваетесь с интерфейсами, а полностью зависите от реализации.

Странно то, что загрузку не делаете рекурсивной, что если у вас у зависимого класса тоже есть зависимость?
Плохо то, что инициализируете сразу все классы, что если их будет много?

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

Отличная идея)) как только в PHP появится инициализация интерфейсов - вернетесь к ней, а пока что забудьте.

Когда наиграетесь - выбрасывайте и переходите на качественные решения, по совету shaqster
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы