Я занимаюсь MVC уже несколько месяцев, и я храню все в моем объекте реестра $ . Когда я создаю новый класс, я только когда-либо пропускаю реестр, но мне приходится постоянно передавать $this->registry
при создании нового класса.
например
class something { public function __construct($registry) { $this->registry = registry; $this->db = $registry->db; $this->user = $registry->user; // ...... } public function something() { $class = new something_class($this->registry); $class->do(); } } class something_class { public function __construct($registry) { $this->registry = $registry; } public function do() { echo 'Doing something ....'; } }
Мой вопрос: как я могу каким-то образом обработать передачу реестра в новый класс за кулисами (в этом случае при создании экземпляра something_class) в классе реестра? Я абсолютно уверен, что есть простой способ сделать это, но я не могу найти ничего связанного нигде с тем, что я ищу.
Вот мой класс реестра :
<?php class registry { protected $vars = array(); public function &__set($index, $value) { $this->vars[$index] = $value; return $value; } public function &__get($index) { return $this->vars[$index]; } }
Это все неправильно. «Registry» – это анти-patter, и то, что вы делаете, не является инъекцией зависимости . Вы нашли способ подделать глобальные переменные .. вот и все.
В начале, пожалуйста, смотрите эту лекцию .
Что касается того, как правильно делать то, что вы хотите, есть два способа:
Чтобы узнать, как вы используете контейнер DI, вам просто нужно обратиться к документации. Но я объясню основы фабрики, которая больше подходит для DIY-подхода
Фабрика – это объект, который отвечает за инициализацию другого класса. Например, у вас есть большой набор классов, которые требуют PDO
в качестве зависимости.
class Factory { private $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function create($name) { return new $name($this->pdo); } }
Если вы используете экземпляр этого класса, это позволит вам создавать объекты, которые PDO уже переданы в качестве зависимости в конструкторе:
$factory = new Factory(PDO($dsn, $user, $pass)); $user = $factory->create('User'); $document = $factory->create('Doc');
И в качестве дополнительной выгоды эта настройка позволила бы использовать экземпляр класса User
и экземпляр класса Doc
для совместного использования одного и того же объекта PDO.
Лучше всего, чтобы ваши классы или компоненты не зависели от вашего контейнера. Пусть ваш контейнер выполняет инъекции зависимостей.
Вот пример, который использует Container из The League of Extraordinary Packages и показывает, что класс B зависит от A:
<?php $container = new League\Container\Container(); $container->add('b', function () { $a = new A('foo'); $b = new B($a); return $b; }); var_dump($container->get('b')->getValueFromA()); // Outputs "foo" class A { private $value; public function __construct($value) { $this->value = $value; } public function getValue() { return $this->value; } } class B { public function __construct(A $a) { $this->a = $a; } public function getValueFromA() { return $this->a->getValue(); } }
Каждый класс, который вы пишете, должен быть связан только с его прямыми зависимостями. По возможности использование интерфейсов настоятельно рекомендуется для дальнейшей развязки.
См. Этот вопрос в Stackoverflow для получения дополнительной информации о различиях между реестром и контейнером DI. Использование реестра считается анти-шаблоном и его следует избегать.
Ваш класс $registry
– это так называемый шаблон Locator . Это полезно в некоторых контекстах, но у него высокий потенциал для злоупотребления, особенно когда вы вводите локатор службы в свой класс.
Предполагается, что инъекция зависимостей должна показывать (показывать) все объекты, которые использует ваш класс (или зависит от них). Внедрение $registry
в ваш класс вместо скрывает зависимости, и именно поэтому это анти-шаблон. Кроме того, это создает для вас бремя, так как вы должны передавать его повсюду, вы также можете сделать его глобальным, чтобы упростить (это также ответит на ваш вопрос). Но лучшие инструменты доступны.
Рассмотрим свой класс следующим образом:
//in your bootstrap or part of your framework $injector = new Auryn\Injector(); $class = $injector->make('something_class'); //Your own code: class something { public function __construct(Database $db, User $user) { $this->db = $db; $this->user = $user; } public function something(something_class $class) { $class->do(); } }
Вы также можете использовать Auryn для выполнения того, что вы хотите сделать, чтобы вызвать класс реестра. Но вскоре вы обнаружите, что Auryn является более надежной версией вашего класса реестра, и это заставляет вас использовать лучшие методы инъекций зависимостей для Auryn для работы по назначению.
Основной момент заключается в том, что ваше собственное приложение (все классы вашего приложения) лучше не знать о каком-либо контейнере. Поскольку в каких контейнерах они скрывают зависимости от ваших классов. Однако остается приемлемым использование контейнеров в рамках структуры. Пусть ваша инфраструктура обрабатывает контейнеры, но вы фокусируетесь на своих собственных классах, не вызывая контейнеры, если эти контейнеры не используются как часть вашей структуры для подключения вашего приложения.