Arr*_*ues 25 php constructor dependency-injection laravel
我正在使用Laravel 4构建CMS,我有一个管理页面的基本管理控制器,如下所示:
class AdminController extends BaseController {
public function __construct(UserAuthInterface $auth, MessagesInterface $message, ModuleManagerInterface $module)
{
$this->auth = $auth;
$this->user = $this->auth->adminLoggedIn();
$this->message = $message;
$this->module = $module;
}
}
Run Code Online (Sandbox Code Playgroud)
我使用Laravel的IOC容器将类依赖项注入构造函数.然后,我有各种控制器类来控制组成CMS的不同模块,每个类都扩展了管理类.例如:
class UsersController extends AdminController {
public function home()
{
if (!$this->user)
{
return Redirect::route('admin.login');
}
$messages = $this->message->getMessages();
return View::make('users::home', compact('messages'));
}
}
Run Code Online (Sandbox Code Playgroud)
现在这完全可行,但是当我向UsersController
类中添加构造函数时,我的问题就出现了问题,这不是问题,而是更多的效率问题.例如:
class UsersController extends AdminController {
public function __construct(UsersManager $user)
{
$this->users = $users;
}
public function home()
{
if (!$this->user)
{
return Redirect::route('admin.login');
}
$messages = $this->message->getMessages();
return View::make('users::home', compact('messages'));
}
}
Run Code Online (Sandbox Code Playgroud)
由于子类现在有一个构造函数,这意味着父类的构造函数没有被调用,因此子类依赖的东西,例如this->user
不再有效,导致错误.我可以通过管理控制器的构造函数调用,parent::__construct()
但是因为我需要传递类依赖项,我需要在子构造函数中设置这些依赖项,从而产生如下所示的内容:
class UsersController extends AdminController {
public function __construct(UsersManager $user, UserAuthInterface $auth, MessagesInterface $message, ModuleManagerInterface $module)
{
parent::__construct($auth, $messages, $module);
$this->users = $users;
}
// Same as before
}
Run Code Online (Sandbox Code Playgroud)
现在这在功能方面运行良好; 但是,对于我来说,必须在具有构造函数的每个子类中包含父级的依赖项似乎并不高效.它看起来也很混乱.Laravel是否提供了解决此问题的方法,或者PHP是否支持调用父和子构造函数而不必parent::__construct()
从子进程调用?
我知道这对于什么是有效的不是问题是一个很长的问题,但更多的我只是关于效率,但我感谢任何想法和/或解决方案.
提前致谢!
没有完美的解决方案,重要的是要了解这不是 Laravel 本身的问题。
要管理此问题,您可以执行以下三件事之一:
将必要的依赖项传递给父级(这是您的问题)
// Parent
public function __construct(UserAuthInterface $auth, MessagesInterface $message, ModuleManagerInterface $module)
{
$this->auth = $auth;
$this->user = $this->auth->adminLoggedIn();
$this->message = $message;
$this->module = $module;
}
// Child
public function __construct(UsersManager $user, UserAuthInterface $auth, MessagesInterface $message, ModuleManagerInterface $module)
{
$this->users = $users;
parent::__construct($auth, $message, $module);
}
Run Code Online (Sandbox Code Playgroud)在父构造中创建实例而不是将它们作为参数传递(因此您不使用依赖注入):
// Parent
public function __construct()
{
$this->auth = App::make('UserAuthInterface');
$this->user = $this->auth->adminLoggedIn();
$this->message = App::make('MessagesInterface');
$this->module = App::make('ModuleManagerInterface');
}
// Child
public function __construct(UsersManager $user)
{
$this->users = $users;
parent::__construct();
}
Run Code Online (Sandbox Code Playgroud)如果你想测试你的类,第三个解决方案将更难测试。我不确定您是否可以使用第二个解决方案来模拟这些类,但是您可以使用第一个解决方案来模拟它们。
我知道这是一个非常古老的问题,但我刚刚在我当前的项目中完成了一个类似的问题,并了解了手头的问题。
这里的基本问题是:
如果我要扩展具有构造函数的父类。该构造函数已注入依赖项,并且其所有依赖项都已记录在父级本身中。为什么我必须在我的子类中再次包含父类的依赖项?
我遇到了同样的问题。
我的父类需要 3 个不同的依赖项。它们是通过构造函数注入的:
<?php namespace CodeShare\Parser;
use CodeShare\Node\NodeRepositoryInterface as Node;
use CodeShare\Template\TemplateRepositoryInterface as Template;
use CodeShare\Placeholder\PlaceholderRepositoryInterface as Placeholder;
abstract class BaseParser {
protected $node;
protected $template;
protected $placeholder;
public function __construct(Node $node, Template $template, Placeholder $placeholder){
$this->node = $node;
$this->template = $template;
$this->placeholder = $placeholder;
}
Run Code Online (Sandbox Code Playgroud)
该类是一个抽象类,因此我永远无法单独实例化它。当我扩展类时,我仍然需要use
在子的构造函数中包含所有这些依赖项及其引用:
<?php namespace CodeShare\Parser;
// Using these so that I can pass them into the parent constructor
use CodeShare\Node\NodeRepositoryInterface as Node;
use CodeShare\Template\TemplateRepositoryInterface as Template;
use CodeShare\Placeholder\PlaceholderRepositoryInterface as Placeholder;
use CodeShare\Parser\BaseParser;
// child class dependencies
use CodeShare\Parser\PlaceholderExtractionService as Extractor;
use CodeShare\Parser\TemplateFillerService as TemplateFiller;
class ParserService extends BaseParser implements ParserServiceInterface {
protected $extractor;
protected $templateFiller;
public function __construct(Node $node, Template $template, Placeholder $placeholder, Extractor $extractor, TemplateFiller $templateFiller){
$this->extractor = $extractor;
$this->templateFiller = $templateFiller;
parent::__construct($node, $template, $placeholder);
}
Run Code Online (Sandbox Code Playgroud)
use
在每个类中包含3 个父依赖项的语句似乎是重复的代码,因为它们已经在父构造函数中定义。我的想法是删除父use
语句,因为它们总是需要在扩展父类的子类中定义。
我意识到,只有use
在父类中进行类型提示时,才需要在父类中包含for 依赖项并在父类的构造函数中包含类名。
如果use
从父构造函数中删除语句并从父构造函数中删除类型提示的类名,则会得到:
<?php namespace CodeShare\Parser;
// use statements removed
abstract class BaseParser {
protected $node;
protected $template;
protected $placeholder;
// type hinting removed for the node, template, and placeholder classes
public function __construct($node, $template, $placeholder){
$this->node = $node;
$this->template = $template;
$this->placeholder = $placeholder;
}
Run Code Online (Sandbox Code Playgroud)
如果没有use
来自父级的语句和类型提示,它就不能再保证传递给它的构造函数的类的类型,因为它无法知道。你可以从你的子类中构造任何东西,而父类会接受它。
看起来确实像重复输入代码,但实际上在您的父级中,您没有使用父级中布置的依赖项进行构建,而是在验证子级是否以正确的类型发送。
归档时间: |
|
查看次数: |
18302 次 |
最近记录: |