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
Еще пришла идея в классы с зависимостями передавать в аргументах интерфейсы, а не объекты.

Прошу заметить что это не полностью рабочий вариант, и прошу дать совет по основной идее работы класса, а не по пропущенным проверкам и тд. Многие моменты максимально облегчены для быстрого понимания
  • Вопрос задан
  • 461 просмотр
Решения вопроса 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
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

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

Похожие вопросы