绑定到 Laravel IoC 而不是一次又一次地实例化
Binding to Laravel IoC instead of instantiating again and again
在我的应用程序中,我有一个名为 "LogService" 的服务来记录事件和其他项目。我基本上需要在每个控制器上使用它来记录用户的事件。不必在每个控制器中实例化此服务,我有两个想法来完成此操作。
选项 1:将服务绑定到 IoC,然后以这种方式解析它
选项 2:创建一个包含服务的主控 class,然后将其扩展到其他 classes,以便它们附带已经绑定的服务
我对这些方法中的每一个都有疑问:
选项 1:这可能吗?如果是这样,它会被调用 "App::make()" 吗?这种方式似乎不太适合IDE的
选项 2:我过去做过这种事情,但 PHPStorm 似乎无法识别来自父对象的服务,因为它是由 "App::make()" 实例化的,而不是通过常规依赖注入。
最好的行动方案是什么?
谢谢!
两种方式都可以,我认为最简洁的方式是:
1) 有一个描述您的 class 的界面,我们称它为 LogServiceInterface
2) 创建一个实例化您的 class 的服务提供者,如下所示:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class LoggerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
$this->app->bind(LogServiceInterface::class, function($app)
{
return new LogService();
});
}
}
3) 在 config/app.ph
文件中注册此服务提供商:
'providers' => [
// Other Service Providers
App\Providers\LoggerServiceProvider::class,
],
4) 现在,在控制器中,您可以直接在构造函数中请求实现 LoggerServiceInterface
的实例:
(某个控制器):
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Repositories\OrderRepository;
class OrdersController extends Controller {
/**
* The logger service.
* @var LoggerServiceInterface $loggerService
*/
protected $loggerService;
/**
* Create a controller instance.
*
* @param OrderRepository $orders
* @return void
*/
public function __construct(LoggerServiceInterface $loggerService)
{
$this->loggerService = $loggerService;
}
/**
* Show all of the orders.
*
* @return Response
*/
public function index()
{
// $this->loggerService will be an instance of your LoggerService class that
// is instantiated in your service provider
}
}
这样,您就有了一种快速更改服务实现的简单方法,而且 Phpstorm 可以非常轻松地处理这个问题。
您仍然可以使用 app()->make()
来获取您的服务实例。
然而,这不会被 Phpstorm 自动拾取。但是你可以帮助它理解,你需要做的就是使用 @var
注解,见:
/**
* @var LoggerServiceInterface $logger
*/
$logger = app()->make(LoggerServiceInterface::class);
That way, Phpstorm will know what to expect from that $logger object.
在我的应用程序中,我有一个名为 "LogService" 的服务来记录事件和其他项目。我基本上需要在每个控制器上使用它来记录用户的事件。不必在每个控制器中实例化此服务,我有两个想法来完成此操作。
选项 1:将服务绑定到 IoC,然后以这种方式解析它
选项 2:创建一个包含服务的主控 class,然后将其扩展到其他 classes,以便它们附带已经绑定的服务
我对这些方法中的每一个都有疑问:
选项 1:这可能吗?如果是这样,它会被调用 "App::make()" 吗?这种方式似乎不太适合IDE的
选项 2:我过去做过这种事情,但 PHPStorm 似乎无法识别来自父对象的服务,因为它是由 "App::make()" 实例化的,而不是通过常规依赖注入。
最好的行动方案是什么?
谢谢!
两种方式都可以,我认为最简洁的方式是:
1) 有一个描述您的 class 的界面,我们称它为 LogServiceInterface
2) 创建一个实例化您的 class 的服务提供者,如下所示:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class LoggerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
$this->app->bind(LogServiceInterface::class, function($app)
{
return new LogService();
});
}
}
3) 在 config/app.ph
文件中注册此服务提供商:
'providers' => [
// Other Service Providers
App\Providers\LoggerServiceProvider::class,
],
4) 现在,在控制器中,您可以直接在构造函数中请求实现 LoggerServiceInterface
的实例:
(某个控制器):
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Repositories\OrderRepository;
class OrdersController extends Controller {
/**
* The logger service.
* @var LoggerServiceInterface $loggerService
*/
protected $loggerService;
/**
* Create a controller instance.
*
* @param OrderRepository $orders
* @return void
*/
public function __construct(LoggerServiceInterface $loggerService)
{
$this->loggerService = $loggerService;
}
/**
* Show all of the orders.
*
* @return Response
*/
public function index()
{
// $this->loggerService will be an instance of your LoggerService class that
// is instantiated in your service provider
}
}
这样,您就有了一种快速更改服务实现的简单方法,而且 Phpstorm 可以非常轻松地处理这个问题。
您仍然可以使用 app()->make()
来获取您的服务实例。
然而,这不会被 Phpstorm 自动拾取。但是你可以帮助它理解,你需要做的就是使用 @var
注解,见:
/**
* @var LoggerServiceInterface $logger
*/
$logger = app()->make(LoggerServiceInterface::class);
That way, Phpstorm will know what to expect from that $logger object.