Laravel: внедрение зависимостей против фасадов?

То, что я делал ранее, - это вводить только МОИ МОДЕЛИ с помощью конструктора и использовать фасады для классов, предоставленных Laravel, например, Session, Auth, Validator и т. Д. Будет ли хорошей идеей внедрять каждый класс (мой или Laravel) через конструкцию и использовать его с помощью синтаксиса $this->.. или я должен внедрить свои собственные классы с помощью конструктора и использовать Фасады для чего-либо, предоставляемого Laravel?

Чтобы быть более конкретным, вот как обычно выглядят мои контроллеры:

class MyController extends BaseController 
{
    public function __construct( User $user, Bookmark $bookmark ) {
        $this->user = $user;
        $this->bookmark = $bookmark
    }

    public function foobar ( ) {
        $user_id = Input::get('bar');
        ...
        Session::get('someInfo');
        ...
        return Redirect::to('/');
    }
    ...
}

Должен ли я вместо этого структурировать свои методы, такие как контроллер, как показано ниже?

class MyController extends BaseController 
{
    public function __construct( User $user, Bookmark $bookmark, Input $input, Session $session, Redirect $redirect ) {
        $this->user = $user;
        $this->bookmark = $bookmark
        $this->input = $input;
        $this->session = $session;
        $this->redirect = $redirect;
    }

    public function foobar ( ) {
        $user_id = $this->input->get('bar');
        ...
        $this->session->get('someInfo');
        ...
        return $this->redirect->to('/');
    }
    ...
}

person Kamran Ahmed    schedule 22.11.2014    source источник
comment
Этот вопрос кажется не по теме, потому что он должен быть на programmers.stackexchange.com.   -  person Florian Margaine    schedule 22.11.2014
comment
Знаете ли вы, почему вам следует вводить объекты вместо использования фасадов Laravel?   -  person Florian Margaine    schedule 22.11.2014
comment
@FlorianMargaine, должно быть фасадами.   -  person tereško    schedule 22.11.2014
comment
Я думаю, что это зависит от вашего мнения о привязке МОК. Если объект будет использоваться во всех / большинстве ваших методов контроллера, имеет смысл перейти к конструкции. Примером может быть: мета (заголовок, описание и т. Д.). Затем вы должны добавить свою привязку в другом месте. Если, с другой стороны, вы редко используете класс во всем приложении, фасад имеет больше смысла. Пример: валидатор, сеанс, перенаправление. (в контексте метода контроллера)   -  person ajameswolf    schedule 23.11.2014


Ответы (4)


Laravel теперь поддерживает те же функции внедрения для методов классов (не только конструкторов), связанных с маршрутами, таких как контроллеры и промежуточное ПО.

Вы можете предотвратить ненужные инъекции, вводя только те методы, в которых зависимость уникальна, возможно, оставив более общие зависимости в конструкторе:

class MyController extends BaseController 
{
    public function __construct( Input $input, Session $session, Redirect $redirect ) {
        $this->input = $input;
        $this->session = $session;
        $this->redirect = $redirect;
    }

    public function foobar ( User $user, Bookmark $bookmark ) {
        $user_id = $this->input->get('bar');
        ...
        $this->session->get('someInfo');
        ...
        return $this->redirect->to('/');
    }
    ...
}

Что касается того, следует ли вам делать это таким образом, решать вам - принудительное отображение всех зависимостей в определениях методов кажется мне более понятным и более простым для модульного тестирования.

person tjbp    schedule 27.01.2016

Элегантно и полезно внедрять определенные классы, такие как Request. На мой взгляд, они должны быть указаны в методах контроллера там, где они необходимы, поскольку затем они логически связаны с реализацией метода. Пока что отлично.

Я считаю, что проблемными являются два фасада - приложение и журнал. Ни тот, ни другой логически не связаны с контроллером или его действиями. Приложение и журнал не являются входными данными ни в каком контексте. Поскольку приложение и журнал являются служебными классами, они также имеют отношение к службам и репозиториям, и становится совершенно неприятно, если вы вводите подсказку в контроллерах, а затем передаете их в качестве параметров конструктора или метода вашим классам поддержки.

Дополнительная проблема заключается в том, что фасад приложения не реализует интерфейс Illuminate \ Contracts \ Auth \ Guard, который он передает через прокси, поэтому моя IDE загорается с предупреждениями, поскольку статический анализ невозможен.

Поэтому для согласованности и общего разделения проблем я бы создал экземпляры приложения и журнала в конструкторе или методе, в зависимости от того, насколько широко они используются в классе. Чтобы моя IDE была довольна, я создал следующий класс, чтобы предоставить мне правильно типизированный экземпляр, где бы он ни был:

<?php namespace App\Components;

use Illuminate\Contracts\Auth\Guard;
use Psr\Log\LoggerInterface;

/**
 * Get the underlying object instances of facades from the container.
 */
class AppGlobal
{
    /**
     * Returns the global logger instance.
     *
     * @return LoggerInterface
     */
    public static function log()
    {
        return app('log');
    }

    /**
     * Returns the global auth instance, which internally proxies a guard.
     *
     * @return Guard
     */
    public static function auth()
    {
        return app('auth');
    }

}
person Dion Truter    schedule 04.02.2017

Если вам нужен объект со свойствами - вставьте его как инъекцию (например, Input, Session ...), в противном случае, если вы не храните никаких данных в объекте и довольно довольны использованием класса, чем используйте фасады (например, Log :: ..., Перенаправить :: ...).

person Yevgeniy Afanasyev    schedule 27.02.2017

Laravel заменил многие фасады, например, помощниками.

use Auth;

и

Auth::user()

сейчас просто

auth()->user()

это делает работу проще и аккуратнее (также предотвращает ошибки)

Я бы посоветовал использовать помощники, где это возможно, и если помощник не существует, использовать фасад, потому что его легче смоделировать, чем внедренный экземпляр.

person lucidlogic    schedule 13.11.2017
comment
Использование обоих описанных вами методов создает ненужную зависимость в коде / тестах и ​​полагается на магию Laravels для разрешения статического Auth :: call. Второй использует вызов глобальной функции, снова создавая зависимость. Лучше инициализировать зависимость в конструкторе и использовать ее. - person Nick; 15.11.2017