{{TOC}} {{DOCVER 4.0=0da300f6445bec5a70d007f503834fce957b065b 16.10.2014 5:19:26, 4.1=efd541a0b218b1c6aafb73f0051c18ed150e3c24 25.05.2014 6:21:03}} == Введение == Класс-контейнер обратного управления **(?IoC Inversion of Control?)** Laravel - мощное средство для управления зависимостями классов. Внедрение зависимостей - это способ исключения вшитых (//hardcoded//) взаимосвязей классов. Вместо этого зависимости определяются во время выполнения, что даёт бо́льшую гибкость благодаря тому, что они могут быть легко изменены. Понимание IoC-контейнера Laravel необходимо для построения больших и мощных приложений, так же как и для внесения изменений в код ядра самого фреймворка. == Основы использования == **Помещение типа в контейнер** Есть два способа, которыми IoC-контейнер разрешает зависимости: через функцию-замыкание и через ((#автоматическое)) определение. Для начала мы исследуем замыкания. Первым делом некий "тип" должен быть помещён в контейнер: %% App::bind('foo', function ($app) { return new FooBar; }); %% **Извлечение типа из контейнера** %% $value = App::make('foo'); %% При вызове метода %%App::make()%% вызывается соответствующее замыкание и возвращается результат её вызова. **Помещение "разделяемого" типа в контейнер** Иногда вам может понадобиться поместить в контейнер тип, который должен быть извлечён (создан) только один раз, и чтобы все последующие вызовы возвращали бы тот же объект: %% App::singleton('foo', function () { return new FooBar; }); %% .(tl_note) **Singleton** - шаблон проектирования ((ВП:Одиночка (шаблон проектирования)==Одиночка)) - //прим. пер.// **Помещение готового экземпляра в контейнер** Вы также можете поместить уже созданный экземпляр объекта в контейнер, используя метод %%instance()%%: %% $foo = new Foo; App::instance('foo', $foo); %% == Где регистрировать привязки == IoC-привязки, как и обработчики событий или фильтры маршрутов, обычно входят в понятие "код автозагрузки". Другими словами они подготавливают ваше приложение к непосредственной обработке запросов, и, как правило, они должны быть выполнены перед вызовом маршрута или контроллера. Как и для большинства другого кода автозагрузки, IoC-привязки всегда можно зарегистрировать в "стартовых" файлах. Кроме того, вы можете создать файл %%(t)app/ioc.php%% (имя файла не имеет значения) и затребовать этот файл из "стартового" файла. Если в вашем приложении очень большое количество IoC-привязок, или вы просто хотите организовать ваши IoC-привязки в отдельных файлах по категориям, вы можете зарегистрировать привязки в ((#поставщики поставщике услуг)). == Автоматическое определение == **Автоопределение класса** Контейнер IoC достаточно мощен, чтобы во многих случаях определять классы автоматически, без дополнительной настройки. Например: %% class FooBar { public function __construct(Baz $baz) { $this->baz = $baz; } } $fooBar = App::make('FooBar'); %% Обратите внимание, что даже без явного помещения класса %%FooBar%% в контейнер он всё равно был определён и зависимость %%Baz%% была автоматически внедрена в него. Если тип не был найден в контейнере, IoC будет использовать возможности //((phpdoc:book.reflection рефлексии))// PHP для изучения класса и чтения подсказок типов (//type hints//) в его конструкторе. С помощью этой информации контейнер сам создаёт экземпляр класса. **Связывание интерфейса и реализации** Однако в некоторых случаях класс может принимать экземпляр интерфейса, а не сам объект. В этом случае нужно использовать метод %%App::bind()%% для извещения контейнера о том, какая именно зависимость должна быть внедрена: %% App::bind('UserRepositoryInterface', 'DbUserRepository'); %% Теперь посмотрим на следующий ((docs/v4/controllers контроллер)): %% class UserController extends BaseController { public function __construct(UserRepositoryInterface $users) { $this->users = $users; } } %% Благодаря тому, что мы связали %%UserRepositoryInterface%% с "настоящим" классом, %%DbUserRepository%%, он будет автоматически встроен в контроллер при его создании. == Практическое использование == Laravel предоставляет несколько возможностей для использования контейнера IoC для повышения гибкости и стабильности вашего приложения. Основной пример - зависимости при использовании ((docs/v4/controllers контроллеров)). Все контроллеры извлекаются из IoC, что позволяет вам использовать зависимости на основе подсказок типов в их конструкторах - ведь они будут определены автоматически. **Подсказки типов для указания зависимостей контроллера** %% class OrderController extends BaseController { // OrderRepository - подсказка типа - имя класса передаваемого аргумента-объекта. public function __construct(OrderRepository $orders) { $this->orders = $orders; } public function getIndex() { $all = $this->orders->all(); return View::make('orders', compact('all')); } } %% В этом примере класс %%OrderRepository%% автоматически встроится в контроллер. Это значит, что при использовании ((docs/v4/testing юнит-тестов)) класс-заглушка для %%OrderRepository%% может быть добавлен в контейнер, таким образом легко имитируя взаимодействие с БД. **Другие примеры использования IoC** ((docs/v4/routing#фильтры_маршрутов Фильтры)), ((docs/v4/responses#составители)) и ((docs/v4/events#классы-обработчики)) могут также извлекаться из IoC. При регистрации этих объектов просто передайте имя класса, который должен быть использован: %% Route::filter('foo', 'FooFilter'); View::composer('foo', 'FooComposer'); Event::listen('foo', 'FooHandler') %% == Поставщики услуг == Поставщики услуг (//service providers//) - отличный способ группировки схожих регистраций в IoC в одном месте. Их можно рассматривать как начальный запуск компонентов вашего приложения. Внутри поставщика услуг вы можете зарегистрировать драйвер авторизации, классы-хранилища вашего приложения или даже собственную команду ((docs/v4/artisan Artisan)). На самом деле большая часть компонентов Laravel включает поставщиков услуг. Все зарегистрированные поставщики в вашем приложении указаны в массиве **providers** файла настроек %%(t)app/config/app.php%%. **Создание поставщика услуг** Для создания нового поставщика просто наследуйте класс %%Illuminate\Support\ServiceProvider%% и определите метод %%register()%%: %% use Illuminate\Support\ServiceProvider; class FooServiceProvider extends ServiceProvider { public function register() { $this->app->bind('foo', function () { return new Foo; }); } } %% Заметьте, что внутри метода %%register()%% IoC-контейнер приложения доступен в свойстве %%$this->app%%. Как только вы создали поставщика и готовы зарегистрировать его в своём приложении просто добавьте его в массив **providers** файла настроек %%(t)app.php%%. **Регистрация поставщика услуг во время выполнения** Кроме этого, вы можете зарегистрировать его "на лету", используя метод %%App::register()%%: %% App::register('FooServiceProvider'); %% == События контейнера == **Регистрация обработчика события** Контейнер IoC возбуждает событие каждый раз при извлечении объекта. Вы можете отслеживать его с помощью метода %%resolvingAny()%%: %% App::resolvingAny(function ($object) { // }); App::resolving('foo', function($foo) { // }); %% Созданный объект будет передан в функцию обратного вызова.