Laravel5.1学习笔记12 系统架构4 服务容器
Service Container
#介绍
The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.
Let's look at a simple example:
Laravel服务容器是管理类依赖的强力工具, 依赖注入是比较专业的说法,真正意思是将类依赖透过构造器,或setter方法注入。 让我们看一个简单的例子。
<?php namespace App\Jobs; use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling; class PurchasePodcast implements SelfHandling
{
/**
* The mailer implementation.
*/
protected $mailer; /**
* Create a new instance.
*
* @param Mailer $mailer
* @return void
*/
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
} /**
* Purchase a podcast.
*
* @return void
*/
public function handle()
{
//
}
}
In this example, the PurchasePodcast job needs to send e-mails when a podcast is purchased. So, we will inject a service that is able to send e-mails. Since the service is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the mailer when testing our application.
这个例子中, 当播客被购买时,PurchasePodcast 命令处理器需要发送一封电子邮件。 所以,我们将注入一个服务来提供这个能力。当这个服务被注入后,我们就可以轻易地切换到不同的实现。 当测试我们的应用程序时, 我们同样也可以轻易地“模拟”,或者创建一个虚拟的发信服务实现,来帮助我们进行测试。
A deep understanding of the Laravel service container is essential to building a powerful, large application, as well as for contributing to the Laravel core itself.
如果要创建一个强大且大型的应用,或者对Laravel的内核做贡献,首先必须对Laravel的服务容器进行深入了解。
#绑定
Almost all of your service container bindings will be registered within service providers, so all of these examples will demonstrate using the container in that context. However, there is no need to bind classes into the container if they do not depend on any interfaces. The container does not need to be instructed how to build these objects, since it can automatically resolve such "concrete" objects using PHP's reflection services.
Within a service provider, you always have access to the container via the $this->appinstance variable. We can register a binding using the bind method, passing the class or interface name that we wish to register along with a Closure that returns an instance of the class:
(这里5.0文档的翻译不准确,让人看得直挠头。 我这样翻译:)几乎所有的服务容器绑定,都发生在服务提供者里面, 所以,所有这些例子都是在上面语境下使用容器时所展现的。然而,没有必要在容器里绑定类,如果它们不依赖任何接口。 容器不需要被告知如何建立这些对象,因为它会使用PHP的反射服务自动解析这个“具体”对象。
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app['HttpClient']);
});
Notice that we receive the container itself as an argument to the resolver. We can then use the container to resolve sub-dependencies of the object we are building.
注意到我们的解析器接收一个容器对象作为引数, 我们然后就可以使用这个容器去解析底下的需要绑定的对象。
绑定一个单例
The singleton method binds a class or interface into the container that should only be resolved one time, and then that same instance will be returned on subsequent calls into the container:
singleton方法绑定一个类或接口到容器里面,而且只会被解析一次, 之后相同的实例在以后的调用会被返回到容器里。
$this->app->singleton('FooBar', function ($app) {
return new FooBar($app['SomethingElse']);
});
绑定一个已存在的实例
You may also bind an existing object instance into the container using the instance method. The given instance will always be returned on subsequent calls into the container:
你也可以使用 instance 方法,绑定一个已经存在的实例到容器, 接下来将总是返回该实例。
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);
#绑定实例到接口
A very powerful feature of the service container is its ability to bind an interface to a given implementation. For example, let's assume we have an EventPusher interface and aRedisEventPusher implementation. Once we have coded our RedisEventPusher implementation of this interface, we can register it with the service container like so:
服务容器一个很强大的特性是他可以给接口绑定一个给定的实现,举例, 让我们假设我们有个EventPusher 接口, 和要给RedisEventPusher 实现, 一旦我们实现了RedisEventPusher, 我们就可以用服务容器来绑定它。
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
This tells the container that it should inject the RedisEventPusher when a class needs an implementation of EventPusher. Now we can type-hint the EventPusher interface in a constructor, or any other location where dependencies are injected by the service container:
这告诉容器,当一个类需要一个EventPusher的实现的时候,它应该注入RedisEventPusher, 现在我们就可以 在类的构造器中类型提示(type-hint)EventPusher接口,或其他容器可以注入依赖的地方。
use App\Contracts\EventPusher; /**
* Create a new class instance.
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}
#上下文绑定(context binding)
Sometimes you may have two classes that utilize the same interface, but you wish to inject different implementations into each class. For example, when our system receives a new Order, we may want to send an event via PubNub rather than Pusher. Laravel provides a simple, fluent interface for defining this behavior:
有时候,你有两个类需要用到同一个接口,但是你希望为每个类注入不同的接口实现。 例如当我们的系统收到一个新的订单时, 我们需要使用PubNub来代替Pusher发送消息。Laravel提供了一个简单便利的接口来定义以上行为
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give('App\Services\PubNubEventPusher');
You may even pass a Closure to the give method:
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give(function () {
// Resolve dependency...
});
#标签
Occasionally, you may need to resolve all of a certain "category" of binding. For example, perhaps you are building a report aggregator that receives an array of many differentReport interface implementations. After registering the Report implementations, you can assign them a tag using the tag method:
偶尔你可能需要解析绑定中的某个类别, 例如你正在建设要给汇总报表,它需要接收实现了Report接口的不同实现的数组。 在注册了Report 的这些实现后,你可以用tag方法来给他们赋予一个标签:
$this->app->bind('SpeedReport', function () {
//
});
$this->app->bind('MemoryReport', function () {
//
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
Once the services have been tagged, you may easily resolve them all via the taggedmethod:
一旦这些服务已经被打标签,就可以用tagged方法轻易解析他们
$this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports')); //这里ReportAggregator接收的是一个数组
});
#解析
There are several ways to resolve something out of the container. First, you may use the make method, which accepts the name of the class or interface you wish to resolve:
有几种方法可从容器中解析出某些东西, 首先,你可以使用 make方法, 它接受一个你希望解析的类或接口的名字
$fooBar = $this->app->make('FooBar');
Secondly, you may access the container like an array, since it implements PHP's ArrayAccessinterface:
第二种,你可以像数组一般使用容器,因为它实现了PHP的ArrayAccess接口
$fooBar = $this->app['FooBar'];
Lastly, but most importantly, you may simply "type-hint" the dependency in the constructor of a class that is resolved by the container, including controllers, event listeners, queue jobs, middleware, and more. In practice, this is how most of your objects are resolved by the container.
The container will automatically inject dependencies for the classes it resolves. For example, you may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class:
最后也是最重要的,你可以在一个类的构造器里面只是去”类型提示”那个依赖,容器会自动注入解析后的类,比如, 你可以在应用的控制器里类型提示一个repository实体类, ,然后实体类会自动被解析然后注入。
<?php namespace App\Http\Controllers; use Illuminate\Routing\Controller;
use App\Users\Repository as UserRepository; class UserController extends Controller
{
/**
* The user repository instance.
*/
protected $users; /**
* Create a new controller instance.
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
} /**
* Show the user with the given ID.
*
* @param int $id
* @return Response
*/
public function show($id)
{
//
}
}
#容器事件
The service container fires an event each time it resolves an object. You may listen to this event using the resolving method:
服务容器每次发出一个解析对象的事件, 你使用resolving 方法侦听:
$this->app->resolving(function ($object, $app) {
// Called when container resolves object of any type...
});
$this->app->resolving(function (FooBar $fooBar, $app) {
// Called when container resolves objects of type "FooBar"...
});
As you can see, the object being resolved will be passed to the callback, allowing you to set any additional properties on the object before it is given to its consumer.
被解析的对象传到闭包方法中,允许你设置其他属性。
Laravel5.1学习笔记12 系统架构4 服务容器的更多相关文章
- Laravel5.1学习笔记i14 系统架构6 Facade
Facades 介绍 使用 Facades Facade 类参考 #介绍 Facades provide a "static" interface to classes th ...
- Laravel5.1学习笔记13 系统架构5 Contract
Contract 简介 为什么要用 Contract? Contract 参考 如何使用 Contract 简介 Laravel 中的 Contract 是一组定义了框架核心服务的接口.例如,Illu ...
- Laravel5.1学习笔记11 系统架构3 服务提供者
服务提供者 简介 写一个服务提供者 Register注册方法 Boot 方法 注册提供者 缓载提供者 简介 Service providers are the central place of all ...
- Laravel5.1学习笔记10 系统架构2 应用程序结构
应用程序结构 简介 根目录 App 目录 为应用程序设置命名空间 简介 默认的 Laravel 应用程序结构是为了给无论构建大型还是小型应用程序都提供一个良好的开始.当然,你可以依照喜好自由地组织应用 ...
- Laravel5.1学习笔记9 系统架构1 请求生命周期 (待修)
Request Lifecycle Introduction Lifecycle Overview Focus On Service Providers Introduction When using ...
- ODI学习笔记2--ODI产品架构
ODI学习笔记2--ODI产品架构 ODI产品架构: ODI提供了以下几种管理工具:Designer 用于定义数据转换逻辑,这是最常用的开发工具,大部分的开发任务,包括data store的定义,in ...
- SQL反模式学习笔记12 存储图片或其他多媒体大文件
目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点: 1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...
- springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定
springmvc学习笔记(12)-springmvc注解开发之包装类型參数绑定 标签: springmvc springmvc学习笔记12-springmvc注解开发之包装类型參数绑定 需求 实现方 ...
- Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点
Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...
随机推荐
- BNUOJ 19792 Airport Express
Airport Express Time Limit: 1000ms Memory Limit: 131072KB This problem will be judged on UVA. Origin ...
- Stones HDU 1896
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1896 题目大意: 有n个石头,每个石头有:p 它所在的位置 ,d 它能扔多远 从0 开始,遇到第奇 ...
- scrapy的User-Agent中间件、代理IP中间件、cookies设置、多个爬虫自定义settings设置
在scrapy的反爬中,常用的几个配置,简单总结了下: User-Agent中间件: from fake_useragent import UserAgent class RandomUserAgen ...
- C# 解决EXCEL单元格合并,行高无法自适应问题
解决方法:根据单元格内容长度,设置单元格所在行的行高 public static float getExcelCellAutoHeight(string strtest, float fontCoun ...
- codevs1001 舒适的线路
题目描述 Description Z小镇是一个景色宜人的地方,吸引来自各地的观光客来此旅游观光.Z小镇附近共有N(1<N≤500)个景点(编号为1,2,3,…,N),这些景点被M(0<M≤ ...
- 洛谷 P1993 小K的农场
P1993 小K的农场 题目描述 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述: 农场a比农场b ...
- Spring/Maven/MyBatis配置文件结合properties文件使用
使用properties文件也叫注入,比如把一些常用的配置项写入到这个文件,然后在Spring的XML配置文件中使用EL表达式去获取. 这种方式不只Spring可以使用,同样MyBatis也可以使用, ...
- ubuntu tweak Install
ubuntu tweak 1:增加PPA源 sudo add-apt-repository ppa:tualatrix/ppa 2:編輯源列表sudo gedit /etc/apt/sources.l ...
- [C++] 自己主动关闭右下角弹窗
近期腾讯.迅雷等各种client,都越发喜欢在屏幕的右下角弹框了. 有骨气的人当然能够把这些软件卸载了事,可是这些client在某些情况下却又还是实用的.怎么办呢? 作为码农,自己实现一个自己主动关闭 ...
- C++学习之new与delete、malloc与free
在C/C++的面试时,对于new/delete和malloc/free这两对的使用和区别经常被考查到,如果这种基础的问题都答不上来,估计很难过面试了.这篇文章仅仅是浅显的讲一下,仅供参考. 一.new ...