系统架构

来自tomtalk
跳转至: 导航搜索

请求生命周期

require __DIR__.'/../bootstrap/autoload.php';
 
$app = require_once __DIR__.'/../bootstrap/app.php';  //创建服务容器
 
/**
 * 创建http核心(或者终端核心)。
 * config/app.php 
 * 1、注册服务提供者
 * 2、boot()
 * 3、注册中间件
 */
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 
 
/**
 * 1、路由分派
 * 2、执行路由中间件
 * 3、跳转到控制器
 */
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
 
$response->send();
 
$kernel->terminate($request, $response);

应用程序结构

服务提供者

服务提供者是所有Laravel应用程序启动的中心所在。包括你自己的应用程序,以及所有的Laravel核心服务,都是通过服务提供者启动的。

若你打开Laravel的config/app.php文件,你将会看到providers数组。这些都是你的应用程序会加载到的所有服务提供者类。当然,它们之中有很多属于「延迟」提供者,意味着除非真正需要它们所提供的服务,否则它们并不会在每一个请求中都被加载。


注册方法

如同之前提到的,在register方法中,你应该只将事物绑定至服务容器中。永远不要尝试在register方法中注册任何事件侦听器、路由或任何其它功能。否则的话,你可能会意外地使用到由尚未加载的服务提供者所提供的服务。


延迟提供者

若你的提供者仅在服务容器中注册绑定,你可以选择延缓其注册,直到真正需要其中已注册的绑定,延迟提供者加载可提高应用程序的性能。

要延迟提供者加载,可将defer属性设置为true,并定义一个provides方法。provides方法会返回提供者所注册的服务容器绑定。

服务容器

在服务提供者中,你总是可以通过$this->app实例变量访问容器。


绑定
  1. 绑定一个单例
  2. 绑定实例
  3. 绑定接口至实现
  4. 情境绑定
  5. 标记


解析

有几种方式可以从容器中解析一些东西。

$fooBar = $this->app->make('FooBar');

或者,你可以像数组一样从容器中进行访问,因为他实现了PHP的ArrayAccess接口:

$fooBar = $this->app['FooBar'];


容器事件

每当服务容器解析一个对象时就会触发事件。你可以使用resolving方法监听这个事件。

Facades

Laravel-Facade实现原理

Facades为应用程序的服务容器中可用的类提供了一个「静态」接口。Laravel本身附带许多的facades,甚至你可能在不知情的状况下已经在使用他们!Laravel「facades」作为在服务容器内基类的「静态代理」,拥有简洁、易表达的语法优点,同时维持着比传统静态方法更高的可测试性和灵活性。

$user = Cache::get('user:'.$id);

如果我们查看Illuminate\Support\Facades\Cache类,你会发现没有静态方法get。

相反的,Cache facade继承了基底Facade类以及定义了getFacadeAccessor()方法。记住,这个方法的工作是返回服务容器绑定的名称。当用户在Cache facade上参考任何的静态方法,Laravel会从服务容器解析被绑定的cache以及针对对象运行请求的方法(在这个例子中是get)。

Facade简化调用的例子

我们使用一个Laravel中的例子,来说明一下Facade是如何简化调用的。我们需要调用设置数据缓存的方法,使用Facade的语法如下:

use Illuminate\Support\Facades\Cache;
 
Route::get('/cache', function() {
 
    // 事先保证执行下面的put方法,将缓存存入
    // Cache::put('key', 'HelloKang', 10);
 
    // 获取缓存项key的内容
    return Cache::get('key');
}

如果不使用Facade来调用,那么调用的语法如下:

Route::get('/cache', function() {   
    // 获取缓存项key的内容
    return app('cache')->get('key');
}


Facade与助手函数

类似于简化语法的操作,除了使用Facade来实现外,Laravel还提供了函数语法,称之为助手函数,helper。其目的都是一致的,就是简化调用语法。

Cache::get('key') 这个语法可以更简单的由 cache('key') 来实现。是不是语法更简单了呢。

其实这两个语法的本质是一样的,我们可以观察 cache() 函数的实现:

定义:/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php

function cache()
{
    $arguments = func_get_args();
 
    // 如果只有一个参数,则解析出cache服务,完成get操作
    if (is_string($arguments[0])) {
        return app('cache')->get($arguments[0], isset($arguments[1]) ? $arguments[1] : null);
    }
 
    // 其他代码略...
 
    // 如果只有两个参数,则解析出cache服务,完成set操作
    return app('cache')->put(key($arguments[0]), reset($arguments[0]), $arguments[1]);
}

可以看出来,cache这个助手函数,也是完成解析服务,调用方法操作的工作。与Facade是一致的!

那么疑问来了:是不是功能重复了?我们该选择使用Facade还是Helper?

是重复了,但是对于Cache来说,仅仅重复了put和get这两个操作。

助手函数,通常仅仅实现了最最常用的服务功能。而Facede就是直接解析出来服务,调用启发方法,换句话说,就是提供完善的服务功能。

总结

  • Facade,就是访问服务方法的快捷语法,不同我们从服务容器中手动解析,直接调用封装好的Facade即可完成任务。
  • 其语法实现是利用PHP类的静态方法重载来实现的。
  • 更加快捷的语法是助手函数,但是助手函数不能提供完善的服务功能,仅仅是最常用的功能,很多时候还是要使用Facade。

Contracts

Laravel的Contracts是一组定义了框架核心服务的接口(php class interfaces)。例如:

  • Illuminate\Contracts\Queue\Queue contract 定义了队列任务所需要的方法
  • Illuminate\Contracts\Mail\Mailer contract 定义了寄送e-mail需要的方法

框架对于每个contract都有提供对应的实现。


Contracts Vs. Facades

Laravel的facades提供一个简单的方法来使用服务,而不需要使用类型提示和在服务容器之外解析contracts。然而,使用contracts可以明显地定义出类的依赖,对大部分应用进程而言,使用facade就足够了,然而,若你实在需要特别的低耦合,使用contracts可以做到这一点。


简单性

当所有的Laravel服务都使用简洁的接口定义,就能够很容易决定一个服务需要提供的功能。可以将contracts视为说明框架特色的简洁文档。

除此之外,当依赖的接口足够简洁时,代码的可读性和可维护性大大提高。比起搜索一个大型复杂的类里有哪些可用的方法,你有一个简单,干净的接口可以参考。