声明:本文并非博主原创,而是来自对《Laravel 4 From Apprentice to Artisan》阅读的翻译和理解,当然也不是原汁原味的翻译,能保证90%的原汁性,另外因为是理解翻译,肯定会有错误的地方,欢迎指正。

欢迎转载,转载请注明出处,谢谢!

服务提供器

启动引导

Laravel服务提供器是往IoC容器中绑定服务的类。事实上,框架核心就是由很多这样的服务提供器驱动管理着容器中绑定的各种资源。基本上框架中的所有组件都是以这种使用提供器注入资源到容器的方式进行注册的。从项目文件app/config/app.php中的providers数组中可以浏览到当前项目使用的提供器列表。

一个服务提供器必须包含至少一种方法:registerregister方法中实现了类绑定到容器的逻辑。当用户发起一个请求时,框架启动,配置文件中定义的服务提供器的register方法会被执行。这在Laravel执行生命周期的早期就会触发,所以,当你的启动文件、比如start目录中的文件加载之后,这些服务启动器就已经可用了。

注册 vs 启动

不要试图在register方法中使用提供器服务。他只是为了将对象绑定到容器中来使用的。所有关于绑定类的后续操作都应在boot方法中完成的。

一些通过Composer安装的第三方类库,都是通过服务提供器进行注入的。类库的安装说明会明确的让你在配置文件中通过向providers数组方法添加配置来使用他们的服务。服务提供器一旦被注册,就可被用于程序的各个地方。

类库服务提供

不是所有的类库都需要服务提供器。实际上,没有类库需要它,服务提供器的作用通常被用来启动组件并使之马上能被使用。他其实就是一个方便我们启动引导代码类库绑定到容器的工具。

延迟提供器

在每次请求中,不是所有的列在providers配置数组中的服务都会被实例化。这对在性能其实是不利的,特别是当他们已经被注册,但是项目中又没有使用到它,这就是一种浪费。比如,QueueServiceProvider服务,只有在那些利用了队列的请求中才会使用到。

为了在请求中,只实例化那些必须的服务,laravel生成了一个“服务器清单”并存储在app/storage/meta目录中。清单中列出了所有应用可能需要用到的服务,也记录了容器需要绑定的类库的名称。当应用中需要使用queue服务时,Laravel知道如何从清单中加载并实例化QueueServiceProvider。这种延迟加载服务的方式,极大的提高了整体的性能。

清单的生成

当在providers数组中添加数据时,Laravel会在下一次请求时自动重新生成清单。

有时间的话,还是要好好看看这个清单的,他对你调试延迟加载服务是非常有帮助的。

组织器

想使用Laravel构建出一个高扩展性良好的应用,那么就有必要学习并将服务提供器作为一种组织工具来管理我们的代码。当向IoC容器注入大量类时,代码都是杂乱的放到app/start文件中来操作的。我们可以使用服务提供器注册服务的方式来代替上面的方式。

万物伊始

应用所有“启动文件”都存放在app/start目录下的。在请求达到应用时,根据请求类型的不同加载相应的“引导”文件。启动文件根据当前环境在start.php之后被加载。例如:artisan.php只在终端命令行模式下被加载。

如下示例。我们的应用可能是在使用Pusher4来进行向用户的消息推送。为了将Pusher进行解耦,这里须要创建一个EventPusherInterface接口和一个PusherEventPuser实现。当需求变更时,我们就能很容易的改变消息服务商。

interface EventPusherInterface{
    public function push($message, array $data = array());
}

class PusherEventPusher implements EventPusherInterface{
    public function __construct(PusherSdk $pusher)
    {
        $this->pusher = $pusher;
    }
    public function push($message, array $data = array())
    {
        // Push message via the Pusher SDK...
    }
}

下面,我们创建一个EventPuserServiceProvider

use IlluminateSupportServiceProvider;

class EventPusherServiceProvider extends ServiceProvider {
    public function register()
    {
        $this->app->singleton('PusherSdk', function()
        {
            return new PusherSdk('app-key', 'secret-key');
        }

        $this->app->singleton('EventPusherInterface', 'PusherEventPusher');
    }
}

赞!我们对时间推送进行了清晰的抽象。同时我们还有一个不错的地方将服务注册绑定到容器中。我们只须要在app/config/app.phpprovider数组中添加EventPusherServiceProvider即可。在接下来的应用中,任何控制器和类都能使用这个注入的服务。

是否须要单例?

我们总需要合适使用bindsingleton。记住一点,一次请求只用一次用singleton,否则用bind

注意:服务提供器的$app变量来自ServiceProvider类中。他是IlluminateFoundationApplication的实例化对象,继承自Container类,所以可以上面一样调用容器中的各种方法。如果你喜欢App这种门面模式,也可以:

App::singleton('EventPusherInterface', 'PusherEventPusher');

当然,服务提供器的功能不止于此,我们也可以注册云存储、数据库访问、自定义模版引擎如Twig等类型的服务。他就是你应用中的引导和管理工具,如此而已。

所以,尽情创建属于你自己的服务提供器吧。这不需要你非得发布个代码包,只是个管理管理工具,来方便应用加载各种项目须要的组件。

启动服务

当所有的服务提供器注册之后,他们就变成了“已启动”状态。每个提供器中的boot方法都会触发。我们通常会犯这样一种错误,就是在register方法试图去调用其他服务。而此时并不能保证所有的服务均已被加载,服务很可能在当前是不可用的,这就会出现错误。因此,我们应该总是在boot方法中去调用其他服务。register方法仅仅是用来将服务注册到容器中。

在boot方法中,你可以做任何事情:注册时间监听器,加载路由文件,注册过滤器,以及任何你能想到的东西。再次提示,把服务提供器作为一种组织工具来使用。也许你希望把一些监听事件组织起来?把他们放到boot方法来实现就是一个很好的方法!或者,你也可以引入一个PHP的“事件”或者“路由”文件:

public function boot()
{
    require_once __DIR__.'/events.php';
    require_once __DIR__.'/routes.php';
}

现在我们已经学习了依赖注入和利用服务提供器来组织项目,我们有了使用Laravel创建可维护、可测试程序的应用架构的强大基础。下面,我们继续深入学习Laravel本身是如何使用服务提供器,框架如何在这个引擎下工作!

别被这些框框束缚了自己

记住,不要老想着只有程序包才能使用服务提供器。要将他作为我们组织服务的好工具。

服务核心

你应该已经注意到app配置文件中已经有很多服务了。每一个都会启动框架核心的各个部分。比如,MigrationServiceProvider负责加载数据库迁移的类库,以及加载Artisan命令;EventServiceProvider负责注册事件调度类。一些服务相对比较负责,但都是负责启动框架核心的某一部分。

约一约这些服务们

理解这些核心服务最好的方法还是去读下源码。如果能对这些服务的源码,和容器的注入非常熟悉,那么Laravel的工作原理也就会变的非常明了了。

大部分的服务都是延迟加载的,并非所有请求都会调用他们;然而框架基本的部分像FilesystemServiceProviderExceptionServiceProvider还是会随请求一起启动的。有些人会说核心服务和容器_就是_Laravel。Laravel就是将所有不同的部分组合成一个单一,内聚的整体。这些服务就是框架这栋大厦的骨架。

再啰嗦一次,想了解Laravel如何工作,还是得看源码,看看框架如何驱动这些核心服务。能明白这些服务如何组织的一块,这些服务如何实现本身的功能。深谙这些之后,也许你也能为Laravel做出自己的贡献!


laravel
101 声望55 粉丝