Php 在laravel facades上使用依赖项注入
我读过很多资料,暗示laravel facade的最终存在是为了方便,这些类应该允许松散耦合。甚至解释如何做到这一点。看来我不是唯一一个这样做的人 将成为Php 在laravel facades上使用依赖项注入,php,laravel,dependency-injection,laravel-facade,Php,Laravel,Dependency Injection,Laravel Facade,我读过很多资料,暗示laravel facade的最终存在是为了方便,这些类应该允许松散耦合。甚至解释如何做到这一点。看来我不是唯一一个这样做的人 将成为 use Illuminate\Routing\Redirector as Redirect; class Example class { protected $redirect; public function __constructor(Redirect $redirect) { $this-&g
use Illuminate\Routing\Redirector as Redirect;
class Example class
{
protected $redirect;
public function __constructor(Redirect $redirect)
{
$this->redirect = $redirect
}
public function example()
{
return $this->redirect->route("route.name");
}
}
这很好,只是我开始发现一些构造函数和方法开始使用4+参数
由于Laravel IoC似乎只注入类构造函数和某些方法(控制器),即使我有相当精简的函数和类,我发现类的构造函数中挤满了所需的类,然后注入所需的方法
现在我发现,如果我继续使用这种方法,我将需要自己的IoC容器,如果我使用像laravel这样的框架,这感觉就像是重新发明轮子
例如,我使用服务来控制业务/视图逻辑,而不是处理它们的控制器——它们只是路由视图。因此,控制器将首先获取其相应的服务
,然后获取其url中的参数
。一个服务函数还需要检查表单中的值,因此我需要Request
和Validator
。就像那样,我有四个参数
// MyServiceInterface is binded using the laravel container
use Interfaces\MyServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Factory as Validator;
...
public function exampleController(MyServiceInterface $my_service, Request $request, Validator $validator, $user_id)
{
// Call some method in the service to do complex validation
$validation = $my_service->doValidation($request, $validator);
// Also return the view information
$viewinfo = $my_service->getViewInfo($user_id);
if ($validation === 'ok') {
return view("some_view", ['view_info'=>$viewinfo]);
} else {
return view("another_view", ['view_info'=>$viewinfo]);
}
}
这是一个单一的例子。实际上,我的许多构造函数已经注入了多个类(模型、服务、参数、外观)。我已经开始将构造函数注入(如果适用)卸载到方法注入,并让调用这些方法的类使用它们的构造函数来注入依赖项
有人告诉我,根据经验,一个方法或类构造函数的四个以上参数是不好的做法/代码味道。然而,我看不出如果你选择注射拉维立面的道路,你怎么能真正避免这种情况
我把这个想法弄错了吗?我的类/功能是否不够精简?我是否遗漏了laravels容器的要点,或者我真的需要考虑创建自己的IoC容器?其他人似乎暗示laravel容器能够消除我的问题
这就是说,在这个问题上似乎没有一个明确的共识…类方法构成了Laravel(中间件、控制器等)路由机制的一部分-它们不都需要注入构造函数中。这可能有助于保持构造函数的苗条,即使我不熟悉任何四参数限制的经验法则;大概是因为需要四个以上的参数并不少见
// MyServiceInterface is binded using the laravel container
use Interfaces\MyServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Factory as Validator;
...
public function exampleController(MyServiceInterface $my_service, Request $request, Validator $validator, $user_id)
{
// Call some method in the service to do complex validation
$validation = $my_service->doValidation($request, $validator);
// Also return the view information
$viewinfo = $my_service->getViewInfo($user_id);
if ($validation === 'ok') {
return view("some_view", ['view_info'=>$viewinfo]);
} else {
return view("another_view", ['view_info'=>$viewinfo]);
}
}
在您的示例中,您可以在构造函数中插入请求
和验证程序
服务作为折衷方案,因为它们通常由多个方法使用
至于建立共识,Laravel必须更加固执己见,以使应用程序足够相似,从而使用“一刀切”的方法。不过,一个更简单的说法是,我认为在未来的版本中,facades会像渡渡鸟一样出现。与其说是一个答案,不如说是一个值得思考的问题,在与我的同事交谈后,他们提出了一些非常有效的观点
好吧,你的想法和顾虑是正确的,我也有。 Facade有一些好处(我通常不使用它们),但是如果你使用just,我建议只在控制器中使用它们,因为控制器至少对我来说只是入口和出口 对于您给出的示例,我将展示我通常如何处理它:
// MyServiceInterface is binded using the laravel container
use Interfaces\MyServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Validation\Factory as Validator;
...
class ExampleController {
protected $request;
public function __constructor(Request $request) {
// Do this if all/most your methods need the Request
$this->request = $request;
}
public function exampleController(MyServiceInterface $my_service, Validator $validator, $user_id)
{
// I do my validation inside the service I use,
// the controller for me is just a funnel for sending the data
// and returning response
//now I call the service, that handle the "business"
//he makes validation and fails if data is not valid
//or continues to return the result
try {
$viewinfo = $my_service->getViewInfo($user_id);
return view("some_view", ['view_info'=>$viewinfo]);
} catch (ValidationException $ex) {
return view("another_view", ['view_info'=>$viewinfo]);
}
}
}
class MyService implements MyServiceInterface {
protected $validator;
public function __constructor(Validator $validator) {
$this->validator = $validator;
}
public function getViewInfo($user_id, $data)
{
$this->validator->validate($data, $rules);
if ($this->validator->fails()) {
//this is not the exact syntax, but the idea is to throw an exception
//with the errors inside
throw new ValidationException($this->validator);
}
echo "doing stuff here with $data";
return "magic";
}
}
只需记住,将代码分解为各个小部分,每个部分都有自己的责任。
当您正确地中断代码时,在大多数情况下,您将不会有那么多构造函数参数,代码将很容易进行测试和模拟
最后一点,如果您正在构建一个小型应用程序,甚至是一个大型应用程序中的一个页面,例如“联系人页面”和“联系人页面提交”,那么您肯定可以使用facades在控制器中完成所有操作,这完全取决于项目的复杂程度。我喜欢laravel,因为它的建筑很漂亮。现在,从我的方法来看,我不会将所有的立面都注入控制器方法,只是为什么?仅在控制器中注入重定向外观是错误的做法,因为它可能需要在其他控制器中注入重定向外观。主要是那些最常用的东西应该被声明,而对于那些使用了一些或者只有使用了它们的人来说,它的最佳实践是通过方法注入它们,就像你在顶部声明的时候一样
/* @var $email_services App\Contracts\EmailServicesContract
$email_services = app('App\Contracts\EmailServicesContract');
protected function dispatch($job)
{
return app('Illuminate\Contracts\Bus\Dispatcher')->dispatch($job);
}
Class PageController
{
public function __construct(
Request $request,
ClientRepositoryInterface $clientrepo,
StaffRepositortInterface $staffRepo
)
{
$this->clientRepository = $clientRepo;
//etc etc
}
public function aboutAction()
{
$teamMembers = $this->staffRepository->getAll();
//render view
}
public function allClientsAction()
{
$clients = $this->clientRepository->getAll();
//render view
}
public function addClientAction(Request $request, Validator $validator)
{
$this->clientRepository->createFromArray($request->all() $validator);
//do stuff
}
}
//think of a better name!
Class ClientCreator
{
public function __construct(Request $request, validator $validator){}
public function getClient(){}
public function isValid(){}
public function getErrors(){}
}
public function addClientAction(ClientCreator $creator)
{
if($creator->isValid()){
$this->clientRepository->add($creator->getClient());
}else{
//handle errors
}
}