Вы правы, в надуманных примерах обычно немного сложно понять, какую именно выгоду вы получаете. Рассмотрим пример контроллера, более близкий к реальному:
class TestController
{
public function __construct(CarRepositoryInterface $car)
{
$this->_repository = $car;
}
public function route($id)
{
return View::make('my.view')->with('car', $this->_repository->find($id));
}
}
Очень просто, репозиторий вводится в конструктор контроллера, который затем используется в маршруте для загрузки определенного автомобиля по идентификатору. Детали репозитория здесь не так уж и важны, и, по-видимому, есть поставщик услуг, который привязывает CarRepositoryInterface
к конкретной CarRepository
реализации:
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('CarRepositoryInterface', function($app) {
return new EloquentCarRepository(new Car());
});
}
}
Итак, вот оно, каждый раз, когда создается контроллер, создается EloquentCarRepository
и вводится в конструктор для использования контроллером.
Но подождите, что произойдет, если вы захотите отказаться от использования Eloquent, чтобы сказать Doctrine? Поскольку здесь мы используем внедрение зависимостей, вам не нужно изменять ни одной строчки кода в вашем контроллере (или любом другом контроллере, который может использовать вашу текущую реализацию). Все, что вам нужно сделать, это определить другую реализацию CarRepositoryInterface
, например DoctrineCarRepository
, и изменить одну строку кода в вашем сервис-провайдере:
return new DoctrineCarRepository();
Все остальное, что зависит от CarRepositoryInterface
, теперь волшебным образом работает. И все это благодаря IoC.
Вы также можете добавить более сложную логику к своему поставщику услуг:
public function register()
{
$this->app->bind('CarRepositoryInterface', function($app) {
if($app->environment() == 'production') {
return new EloquentCarRepository(new Car());
} else {
return new DoctrineCarRepository(new Car());
}
});
}
Здесь EloquentCarRepository
будет использоваться только в производственной среде, тогда как в любой другой среде будет использоваться DoctrineCarRepository
. (Этот пример предназначен только для того, чтобы показать, как вы можете получить гораздо больший контроль над типом объекта, создаваемым во время выполнения, а не то, что я выступаю за это на самом деле ..)
Дополнение
Как я сказал в своем комментарии, это тип использования, при котором вы не совсем уверены, какой тип объекта вам понадобится, до времени выполнения. Есть еще одно применение: управление зависимостями.
Предположим, у вас есть объект, который зависит от другого объекта:
class MyObject
{
public function __construct(AnotherObject $obj)
{
$this->obj = $obj;
}
}
Предположим также, что AnotherObject
зависит от еще одного объекта:
class AnotherObject
{
public function __construct(YetAnotherObject $obj)
{
$this->obj = $obj;
}
}
Это может быстро выйти из-под контроля, и вы можете столкнуться с длинными цепочками зависимостей, которые необходимо удовлетворить, прежде чем вы действительно сможете создать объект. С помощью IoC вы можете просто извлечь экземпляр из контейнера:
$myObject = app()->make('MyObject');
Пока IoC может построить все зависимости, вам не нужно делать что-то вроде этого:
$yetAnotherObj = new YetAnotherObject();
$anotherObj = new AnotherObject($yetAnotherObj);
$myObject = new MyObject($anotherObj);
person
Jeff Lambert
schedule
11.08.2014