Контейнеры, буквально, – это вещи, в которых что-то хранится. Общие переменные и свойства объектов можно рассматривать как контейнеры. То, что может вместить контейнер, зависит от вашего определения контейнера. Конечно, есть такой контейнер, который хранит не текст или значения, а описания (классы и интерфейсы) объектов и объектов или обеспечивает обратный вызов объектов. С помощью такого контейнера мы можем реализовать множество расширенных функций, среди которых наиболее часто упоминаются “развязка” и “внедрение зависимостей (DI)”. Эта статья начинается здесь.
Контейнер IOC, ядро laravel
Ядром laravel является Контейнер IoC , согласно документу, он называется” Сервисный контейнер “, как следует из названия, этот контейнер предоставляет ряд услуг, необходимых во всей структуре. Как новичок, у многих людей возникнут трудности с этой концепцией. Поэтому я намерен начать с некоторого базового содержания и постепенно приоткрыть завесу “внедрения зависимостей” и понять эту волшебную концепцию дизайна, поняв создание и решение зависимости в объектно-ориентированной разработке.
Большая часть содержания этой статьи состоит в том, чтобы дать читателям пример, чтобы понять, что такое IOC (инверсия контроля) и di (внедрение зависимостей). Понимая эти концепции, мы можем пойти глубже. Для получения дополнительной информации об использовании контейнера службы laravel, пожалуйста, ознакомьтесь с документом.
История рождения контейнера МОК
Есть много статей о контейнерах IOC, которые я писал раньше. Но теперь я собираюсь использовать текущее вдохновение, чтобы сделать это снова, так что давайте начнем.
Супермен и сверхдержава, порождение зависимости!
В объектно-ориентированном программировании всегда есть следующие вещи в контакте: Интерфейс 、 класс Также объект 。 Среди них интерфейс является прототипом класса, и класс должен соответствовать интерфейсу, который он реализует; объект-это созданный продукт класса, который мы называем экземпляром. Конечно, это, безусловно, не способствует пониманию, мы действительно можем писать пункты в коде, чтобы помочь в обучении.
Мир монстров нуждается в некоторых супер персонажах, чтобы справиться с ним.
Мы берем супермена за класс,
class Superman {}Мы можем себе представить, что, когда рождается супермен, он должен обладать по крайней мере одной сверхспособностью. Эта сверхдержава также может быть абстрагирована как объект. Определите класс для описания этого объекта. Для сверхдержавы должно быть несколько атрибутов и методов (работы), что является искренним воображением. В настоящее время мы примерно определяем “сверхдержаву” только с атрибутами. Что касается того, что мы можем сделать, мы обогатим его позже:
class Power {
/**
* capacity value
*/
protected $ability;
/**
*Capability range or distance
*/
protected $range;
public function __construct($ability, $range)
{
$this->ability = $ability;
$this->range = $range;
}
}В это время мы вернемся и изменим предыдущий класс “Супермен”, чтобы при создании “Супермена” ему была предоставлена суперспособность:
class Superman
{
protected $power;
public function __construct()
{
$this->power = new Power(999, 100);
}
}Таким образом, когда мы создаем экземпляр “Супермена”, мы также создаем экземпляр “сверхдержавы”. Однако мы видим, что существует неизбежная зависимость между “Суперменом” и “сверхдержавой”.
Так называемая “зависимость”-это “если я завишу от тебя, я не смогу тебя бросить”.
В проекте реализации объектно-ориентированного программирования такую зависимость можно увидеть повсюду. Небольшое количество зависимостей не окажет слишком интуитивного влияния. Мы постепенно распространим этот пример и позволим вам постепенно осознать, каким кошмаром является переживание, когда зависимость достигает определенного уровня. Конечно, я, естественно, расскажу о том, как решить эту проблему.
Беспорядок – ужасная зависимость
В предыдущем примере экземпляр класса суперспособностей является определенной суперспособностью. Однако мы знаем, что сверхспособности Супермена разнообразны, а методы и атрибуты каждой сверхспособности различны, что не может быть полностью описано одним видом. Давайте изменим его сейчас. Давайте предположим, что Супермен может обладать следующими видами способностей:
- Полет: скорость и продолжительность полета
- Грубая сила: значение силы
- Энергетическая бомба, атрибуты: величина урона, дальность стрельбы, количество одновременных выстрелов
Мы создали следующие классы:
class Flight
{
protected $speed;
protected $holdtime;
public function __construct($speed, $holdtime) {}
}
class Force
{
protected $force;
public function __construct($force) {}
}
class Shot
{
protected $atk;
protected $range;
protected $limit;
public function __construct($atk, $range, $limit) {}
}*Чтобы избавить вас от лишних хлопот, я не написал все детали конструктора, только параметры, которые необходимо передать.
Ну, наш Супермен немного занят. Когда Супермен инициализируется, мы создадим его суперсилу по мере необходимости, примерно следующим образом:
class Superman
{
protected $power;
public function __construct()
{
$this->power = new Fight(9, 100);
// $this->power = new Force(45);
// $this->power = new Shot(99, 50, 2);
/*
$this->power = array(
new Force(45),
new Shot(99, 50, 2)
);
*/
}
}Нам нужно вручную создать экземпляр ряда необходимых классов в конструкторе (или других методах), что нехорошо. Как вы можете себе представить, если спрос изменится (разные монстры путешествуют по земле), появятся более целенаправленные Новые Способности или потребуется изменение Суперсилы, нам придется Реинжиниринг Супермена. Другими словами, когда я меняю свои способности, я должен воссоздать супермена Слишком неэффективно! Мир уже был разрушен до того, как был создан новый Супермен.
В это время человек с идеей подумал: почему это не может быть так? Способности Супермена могут быть изменены в любое время, просто нужно добавить или обновить чип или другие устройства (вспомните железного человека). Таким образом, вам не придется делать это снова и снова.
Да, именно так.
Мы не должны вручную закреплять поведение инициализации его “суперспособности” в классе “Супермен”, а возложить на него внешнюю ответственность за создание модулей, устройств или чипов суперспособностей (в будущем мы будем называть их “модулями”) и вживлять определенный интерфейс в тело Супермена. Этот интерфейс является заданным, до тех пор, пока “модуль” соответствует устройствам этого интерфейса, может использоваться Суперменом, может усиливать, увеличивать определенные способности Супермена. Такого рода поведение, которое внешне отвечает за его зависимые требования, можно назвать” Инверсия контроля (IOC) “.
Заводской режим, передача зависимостей!
Конечно, существует несколько способов добиться инверсии контроля. А перед этим давайте сначала узнаем что-нибудь интересное.
Мы можем думать о компонентах и инструментах (или сверхчеловеческих модулях) как о чем-то, что может быть произведено. Конечно, местом производства является “фабрика”. Поэтому кто-то предложил такой режим: Заводской режим 。
Фабричный шаблон, как следует из названия, – это шаблон разработки, который может быть создан одной или несколькими “фабриками”, например, внешних вещей, от которых зависит класс” Заводской режим “.
Для того, чтобы сделать супермощные модули для Супермена, мы создали фабрику, которая может производить все виды модулей, и только одним способом:
class SuperModuleFactory
{
public function makeModule($moduleName, $options)
{
switch ($moduleName) {
case 'Fight': return new Fight($options[0], $options[1]);
case 'Force': return new Force($options[0]);
case 'Shot': return new Shot($options[0], $options[1], $options[2]);
}
}
}В это время Супермен может использовать эту фабрику в начале ее создания!
class Superman
{
protected $power;
public function __construct()
{
//Initialize factory
$factory = new SuperModuleFactory;
//Manufacture the required modules by the method provided by the factory
$this->power = $factory->makeModule('Fight', [9, 100]);
// $this->power = $factory->makeModule('Force', [45]);
// $this->power = $factory->makeModule('Shot', [99, 50, 2]);
/*
$this->power = array(
$factory->makeModule('Force', [45]),
$factory->makeModule('Shot', [99, 50, 2])
);
*/
}
}Можно видеть, что нам больше не нужно инициализировать многие сторонние классы в начале инициализации Супермена. Нам просто нужно инициализировать заводской класс для удовлетворения потребностей. Но, похоже, это не так сильно отличается от предыдущего, просто не так сильно новое Ключевое слово. На самом деле, если мы немного изменим эту категорию, вы поймете истинное значение и ценность заводской категории.
class Superman
{
protected $power;
public function __construct(array $modules)
{
//Initialize factory
$factory = new SuperModuleFactory;
//Manufacture the required modules by the method provided by the factory
foreach ($modules as $moduleName => $moduleOptions) {
$this->power[] = $factory->makeModule($moduleName, $moduleOptions);
}
}
}
//Create Superman
$superman = new Superman([
'Fight' => [9, 100],
'Shot' => [99, 50, 2]
]);Теперь результат модификации удовлетворителен. Теперь создание “Супермена” больше не зависит от какого-либо класса “суперспособностей”. Если мы изменим или добавим новую суперспособность, нам нужно будет только изменить ее Фабрика супермодулей Да. Нам очень легко расширить суперспособность, не редактируя файл класса superhuman снова. Но это только начало.
Дальше! Важный компонент контейнера IOC – инъекция зависимостей!
От зависимости Супермена от сверхдержавы до зависимости Супермена от фабрики модулей сверхдержавы становится все удобнее иметь дело с маленькими монстрами. Но, как вы можете видеть, зависимость не была снята, а изменилась с зависимости от множества внешних факторов на зависимость от “фабрики”. Если на заводе возникнут какие-либо проблемы, проблема будет очень сложной.
В большинстве случаев достаточно заводской модели. Недостатком заводского шаблона является то, что интерфейс неизвестен (т. Е. Нет хорошей контрактной модели, которую я немедленно объясню), а сгенерированный тип объекта является единым. Одним словом, он все еще недостаточно гибок. Тем не менее, заводская модель по-прежнему превосходна и применима в большинстве случаев. Но мы собираемся поговорить о Инъекции зависимостей Прежде всего, я преувеличу недостатки заводской модели.
Мы знаем, что нам нужен единый интерфейс для модулей, зависящих от Супермена, чтобы мы могли взаимодействовать с интерфейсом впрыска Супермена и, наконец, улучшить суперспособности.
На самом деле, я лгал раньше, не только кучке маленьких монстров, но и более крупным монстрам. Эй. Ну, похоже, что производственных мощностей завода в настоящее время недостаточно. В заводском режиме все модули расположены в заводском классе. Если добавляются новые и расширенные модули, мы должны изменить класс фабрики (например, добавить новые производственные линии).:
class SuperModuleFactory
{
public function makeModule($moduleName, $options)
{
switch ($moduleName) {
case 'Fight': return new Fight($options[0], $options[1]);
case 'Force': return new Force($options[0]);
case 'Shot': return new Shot($options[0], $options[1], $options[2]);
// case 'more': .......
// case 'and more': .......
// case 'and more': .......
// case 'oh no! its too many!': .......
}
}
}
Видеть… Кошмарное чувство!
На самом деле, вдохновение в одном шаге от вас! Вы можете придумать более гибкий способ! Да, следующий шаг – это наша главная вспомогательная роль сегодня-di (внедрение зависимостей).
В связи с растущим спросом на супермощный модуль нам необходимо собрать таланты с высоким интеллектом всего мира, чтобы вместе решить эту проблему, а не только несколько заводов несут ответственность за монополию. Однако люди с высоким интеллектом очень тщеславны и думают, что их идеи верны. Созданный ими модуль super power не имеет единого интерфейса, поэтому его нельзя использовать нормально. В это время нам нужно предложить контракт, чтобы независимо от того, кто создает модуль, он соответствовал такому интерфейсу и его можно было использовать нормально.
interface SuperModuleInterface
{
/**
*Activation method of super ability
*
*Any super power has to have this method and have a parameter
*@Param array $target is for the target, which can be one or more, oneself or others
*/
public function activate(array $target);
}В приведенном выше, мы определили интерфейс (спецификация и контракт супер модуля). Все созданные модули должны соответствовать спецификации, прежде чем их можно будет изготовить.
На самом деле, это PHP Интерфейс (Interface) Использование и значение! Многие люди думают, зачем PHP нужны интерфейсы? Разве это не просто язык, такой как Java и C? Итак, пока это обычный объектно-ориентированный язык программирования (хотя PHP может быть ориентирован на процессы), он должен обладать этой функцией. Потому что один Объект (объект) Это его шаблон или прототип– Класс После создания экземпляра создается определенный объект. Иногда при реализации единого метода и различных функций (или функций) возникает множество классов. В этом случае необходим контракт, чтобы заставить вас написать интерфейс, который можно заменить в любое время без каких-либо последствий. Эта жесткая спецификация, предложенная самим языком программирования, добавит больше отличных функций.
Хотя есть некоторые обходные пути, на наших следующих примерах вы постепенно поймете преимущества интерфейса.
В настоящее время те таланты с высоким IQ, которые предлагают лучшие модули суперспособностей, следуют этому интерфейсу и создают следующие классы (модули):
/**
*X-super energy
*/
class XPower implements SuperModuleInterface
{
public function activate(array $target)
{
//This is just an example.. Specific autonomic brain supplement
}
}
/**
*The ultimate bomb
*/
class UltraBomb implements SuperModuleInterface
{
public function activate(array $target)
{
//This is just an example.. Specific autonomic brain supplement
}
}В то же время, чтобы помешать некоторым “каменщикам” создавать свои собственные умные, или некоторым предателям совершать озорные трюки, не соблюдать контракт, создавать модули случайным образом и влиять на Супермена, мы изменили метод инициализации Супермена:
class Superman
{
protected $module;
public function __construct(SuperModuleInterface $module)
{
$this->module = $module
}
}Трансформация завершена! Теперь, когда мы инициализируем класс Superman, предоставленный экземпляр модуля должен быть Интерфейсом супер модуля Реализацией интерфейса. В противном случае будет выведено сообщение об ошибке.
Просто потому, что создание Супермена становится легким, супермену не нужно слишком много сверхспособностей. Мы можем создать несколько Суперменов и соответственно ввести необходимые модули суперсилы. Таким образом, хотя у Супермена есть только одна сверхдержава, Супермен с большей вероятностью изменится, и мы не боимся монстров!
Теперь кому-то интересно, о чем вы собираетесь говорить Инъекция зависимостей Как насчет этого?
На самом деле, вышеприведенный контент-это просто инъекция зависимостей.
Что называется Инъекцией зависимостей ?
Ряд зависимостей, упомянутых в этой статье с самого начала и до настоящего времени, если они не созданы внутренне (например, инициализация, конструктор __конструкция Он вводится внешними параметрами или другими формами с помощью заводского метода и вручную. Это относится к Инъекции зависимостей (DI) . Это вдруг стало ясно? На самом деле, все так просто. Вот типичная инъекция зависимостей:
//Super power module $superModule = new XPower; //Initializes a superman and injects a superpower module dependency $superMan = new Superman($superModule);
Так много можно сказать о внедрении зависимостей, главной вспомогательной роли этой статьи. С пониманием внедрения зависимостей мы можем пойти дальше. Подойдите ближе к сегодняшнему главному герою
Более продвинутый заводской контейнер IOC!
Просто перечислил код:
$superModule = new XPower; $superMan = new Superman($superModule);
Читатель должен видеть, что модуль сверхдержавы был создан вручную, сверхчеловек был создан вручную, и только что был создан модуль сверхдержавы. Ха-ха, инструкция.
В современном обществе это должно быть эффективное производство, чистый цех и совершенная автоматическая сборка.
Группа монстров приближается. Нереально создать Супермена с такой низкой эффективностью. Нам нужна автоматизация – самое большее по одной команде тысячи военнослужащих встретятся друг с другом. Нам нужен производственный цех высокого уровня, нам просто нужно отправить сценарий в производственный цех, и фабрика может автоматизировать производство с помощью инструкций. Эта фабрика более высокого уровня является сублимацией заводского режима– Контейнер IoC 。
class Container
{
protected $binds;
protected $instances;
public function bind($abstract, $concrete)
{
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
public function make($abstract, $parameters = [])
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
array_unshift($parameters, $this);
return call_user_func_array($this->binds[$abstract], $parameters);
}
}В это время родился очень грубый контейнер. Сейчас это действительно просто, но это не мешает нам продвигать его дальше. Теперь давайте посмотрим, как использовать этот контейнер!
//Create a container (called super factory later)
$container = new Container;
//Add Superman's production script to the super factory
$container->bind('superman', function($container, $moduleName) {
return new Superman($container->make($moduleName));
});
//Add production script of super module to the super factory
$container->bind('xpower', function($container) {
return new XPower;
});
// ibid.
$container->bind('ultrabomb', function($container) {
return new UltraBomb;
});
//The gorgeous dividing line**********************
//Start production
$superman_1 = $container->make('superman', ['xpower']);
$superman_2 = $container->make('superman', ['ultrabomb']);
$superman_3 = $container->make('superman', ['xpower']);
//... add at willВидишь? С помощью оригинальной операции Bind мы зарегистрировали некоторые производственные сценарии на суперфабрике, которые будут выполнены при выпуске производственного заказа. Ты узнал об этом? Мы полностью устранили зависимость между Суперменом и модулем суперсилы. Что еще более важно, класс контейнера вообще не зависит от них! Мы добавляем обратный вызов (анонимная функция, неанонимная функция, метод класса) в контейнер посредством регистрации и привязки в качестве экземпляра для создания класса Сценария , только в реальном Производстве (make) Только когда операция вызывается для выполнения.
Такой способ облегчает нам решение отношений зависимости при создании экземпляра и делает его более гибким. Когда появятся новые требования, просто свяжите другой “производственный сценарий”.
На самом деле, настоящий контейнер IOC более продвинут. В нашем текущем примере нам все еще нужно вручную указать параметры модуля, требуемые Superman, но реальный контейнер IOC автоматически выполнит поиск зарегистрированных и связанных экземпляров для удовлетворения требований к зависимостям в соответствии с требованиями к зависимостям класса и автоматически введет их в параметры конструктора. Это то, что делает сервисный контейнер платформы laravel. На самом деле, реализовать эту функцию в теории не составляет особого труда, но я не буду писать об этом в этой статье, потому что мне лень писать.
Но я вам скажу, что функция автоматического поиска зависит от требований через Отражение Реализована, точно, PHP отлично поддерживает механизм отражения! О рефлексии, официальные документы PHP содержат подробную информацию и базовое освещение китайского перевода, достаточно обучения и исследований!
http://php .net/руководство/ж/книга…
Теперь, до сих пор, мы больше не боимся монстров. Таланты с высоким IQ хорошо организованы и проводят мозговые штурмы, а также создают стандартные модули суперспособностей в соответствии с контрактом на интерфейс. Супермена начали выпускать партиями. В конце концов, все люди-Супермены, так же как и вы !
Вернитесь в нормальный мир. Мы начали пересматривать суть laravel.
Теперь давайте медленно начнем понимать суть laravel. Фактически, ядром laravel является контейнер IOC, который, как оказалось, является усовершенствованным контейнером IOC, о котором я упоминал ранее.
Можно сказать, что ядро самого laravel очень легкое, и в нем нет волшебной и существенной прикладной функции. Многие люди используют различные функциональные модули, такие как Маршрут 、 Красноречивый ORM (компонент ORM базы данных) 、 Запрос и ответ И так далее. Фактически, эти классы предоставляются основными независимыми модулями классов. Эти классы используются вами от регистрации до создания экземпляра. На самом деле за них отвечает сервисный контейнер laravel.
В качестве примера мы используем наиболее распространенный класс Route . Вы часто можете видеть определение маршрута следующим образом:
Route::get('/', function() {
// bla bla bla...
});На самом деле, Маршрут Класс определен в этом пространстве имен: Осветить\Маршрутизация\Маршрутизатор Файл vendor/laravel/framework/src/Illuminate/Routing/Router.php 。
Открыв, мы обнаруживаем, что эта серия методов этого класса, таких как get , post , any Wait, не является статическим методом. В чем дело? Не волнуйся, давай продолжим.
Поставщик услуг
В предыдущем разделе введения контейнеров IOC мы упоминали, что класс должен быть привязан и зарегистрирован в контейнере, чтобы быть “изготовленным”.
Да, если класс должен быть извлечен контейнером, он должен быть сначала зарегистрирован в контейнере. Поскольку laravel называет этот контейнер контейнером службы, если нам нужна служба, нам сначала нужно зарегистрироваться и привязать службу к контейнеру. Что нам нужно для предоставления и привязки услуги к контейнеру, так это Поставщик услуг 。
Однако привязка класса к контейнеру не обязательно должна проходить через поставщика услуг .
Однако мы знаем, что иногда нашим классам и модулям нужны другие классы и компоненты. Чтобы гарантировать, что необходимые модули и компоненты не будут зарегистрированы на этапе инициализации, laravel разделит поведение регистрации и инициализации. При регистрации он может только регистрироваться, а при инициализации-это инициализация. Продукт теперь Поставщик услуг 。
Поставщик услуг в основном разделен на две части: Регистрация (регистрация) и Загрузка (загрузка, инициализация) , подробности см. в документе. зарегистрируйтесь Несите ответственность за регистрацию “скрипта” в контейнере, но будьте осторожны, чтобы не полагаться на неизвестное в части регистрации. Если это так, перейдите в раздел загрузка Часть.
Фасад
Давайте теперь ответим на предыдущие вопросы о Маршруте Вопрос о том, как можно получить доступ к статическим методам. На самом деле, эта проблема написана в документе, который заключается в моделировании класса и предоставлении статического магического метода __callStatic и сопоставлении статического метода с реальным методом.
Мы используем Маршрут Класс на самом деле Осветить\Поддержка\Фасады\Маршрут принять class_alias() Функция создана псевдоним Просто этот класс определен в файле vendor/laravel/framework/src/Illuminate/Support/Facades/Route.php 。
Давайте откроем файл и посмотрим, а? Как мог существовать такой простой фрагмент кода?
На самом деле, если вы присмотритесь, вы обнаружите, что этот класс наследует класс под названием Фасад Мы должны разгадать тайну.
В приведенном выше простом определении мы видим, что getFacadeAccessor Метод возвращает маршрут Что это значит? На самом деле это значение Поставщик услуг Зарегистрирован, мы должны знать, что зарегистрирован, конечно, реальный класс маршрутизации!
Некоторые люди спросят, как реализован фасад. Я не хочу быть слишком конкретным. Во – первых, я ленив. Во-вторых, я нахожу, что некоторые вещи легче понять и нелегко забыть. Я уже рассказал много подробностей, и я предлагаю вам изучить их самостоятельно.
До сих пор мы говорили почти обо всем.
Мир! Пришло время подвести итоги!
В любом случае, мир спокоен.
Здесь я хочу подвести итог тому, что многие вещи не являются сложными, и чего я боюсь, так это сложного теоретического содержания. Я думаю, что многие вещи становятся одинаковыми, как только они выясняются. Многие люди думают, что laravel нехорош, это нехорошо, и это здесь сложно. Я могу только сказать, что laravel не является первоклассным и отличным фреймворком. Я могу сказать, что laravel-первоклассный и отличный фреймворк, а не поклонник laravel или поклонник laravel. Самая большая особенность и превосходство laravel заключается в том, что он использует множество относительно новых (на самом деле не новых) концепций и технологий (всего лишь набор грамматического сахара) в PHP. Таким образом, laravel действительно подходит для обучения. Идея Laravel действительно сильно отличается от других фреймворков, что требует, чтобы люди, которые его изучают, должны владеть PHP и Прочным фундаментом ! Если вам очень трудно освоить фреймворк laravel, есть только одна причина: ваша основа PHP не очень хороша.
Кроме того, будучи хорошим специалистом по использованию пространства имен и объектно-ориентированных функций для достижения чего-либо, вы обнаружите, что это так просто.