将接口绑定到实现
注入具体依赖
服务容器有个非常强大特色,能够绑定特定实例的接口。举例,假设我们应用程序要集成 Pusher 服务去收发即时事件,如果使用 Pusher 的 PHP SDK,可以在类注入一个 Pusher 客户端实例:
<?php namespace App\Handlers\Commands;
use App\Commands\CreateOrder;
use Pusher\Client as PusherClient;
class CreateOrderHandler {
/**
* Pusher SDK 客户端实例
*/
protected $pusher;
/**
* 创建一个实例
*
* @param PusherClient $pusher
* @return void
*/
public function __construct(PusherClient $pusher)
{
$this->pusher = $pusher;
}
/**
* 执行命令
*
* @param CreateOrder $command
* @return void
*/
public function execute(CreateOrder $command)
{
//
}
}
在上面这个例子中,注入类的依赖到类中已经能够满足需求;但同时,我们也紧密耦合于 Pusher 的 SDK 。如果 Pusher 的 SDK 方法发生改变,或者我们要切换到别的事件服务,那我们也需要同时修改 CreateOrderHandler 的代码。
为接口编程
为了将 CreateOrderHandler 和事件推送的修改「隔离」,我们可以定义一个 EventPusher 接口和一个 PusherEventPusher 实现:
<?php namespace App\Contracts;
interface EventPusher {
/**
* Push a new event to all clients.
*
* @param string $event
* @param array $data
* @return void
*/
public function push($event, array $data);
}
一旦 PusherEventPusher 实现这接口,就可以在服务容器像这样注册它:
$this->app->bind('App\Contracts\EventPusher', 'App\Services\PusherEventPusher');
当有类需要 EventPusher 接口时,会告诉容器应该注入 PusherEventPusher,现在就可以在构造器中「类型指定」一个 EventPusher 接口:
/**
* Create a new order handler instance.
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}