对laravel中核心概念的理解
一. 请求周期(Lifecycle)
laravel的生命周期从public/index.php文件开始,public文件夹主要存放了web前端资源文件及配置文件,index.php作为请求的入口,主要对laravel应用的初始化和对请求生命周期的管理。在index.php中,主要实现了对第三方依赖的加载,生成服务器容器及处理请求。
1.加载composer依赖
1
| require __DIR__.'/../vendor/autoload.php';
|
同js的包管理工具npm一样,通过composer加载vendor目录下的第三方依赖库。
2.生成服务容器,app实例。通过服务提供者向容器注册核心组件(HttpKernel,ConsoleKernel,ExceptionHandler)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| $app = require_once __DIR__.'/../bootstrap/app.php'; $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class ); $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class );
|
创建服务器容器,通过服务提供器方法绑定http的接口与实现,Console的接口与实现,Debug的接口与实现。
3.处理请求
1 2 3 4 5 6 7 8 9
| $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); $response->send(); $kernel->terminate($request, $response);
|
通过make方法实例化Illuminate\Contracts\Http\Kernel,通过handle方法处理请求,生成并发送响应,通过terminate结束请求。
二. 服务器容器(Service Container)
服务器容器是存放类的实例的容器,在laravel运行过程中,自动加载需要用到的类对象,注册到容器中,通过容器管理其生命周期,在业务逻辑的实现过程中可以直接通过容器获取使用,无需关心其生成。把对类的创建和管理权的转移称为控制反转,通过控制反转减少对第三的类的控制权并统一交由容器管理。例:
1 2 3 4 5 6 7 8 9 10 11
| class A { protected $b; public __construct() { $this->b = new B(); } }
|
控制反转(IoC)后,将类B的控制权交由服务器容器app。
1 2 3 4 5 6 7 8 9
| class A { protected $b; public __construct() { $this->app->make('\B'); } }
|
laravel中服务器容器(app)通过bind方法把需要绑定的类的实例注册到容器中,使用时,通过make方法解析。绑定需要服务提供方法,操作一般在ServiceProviders中的register方法中,最基本的绑定是容器的bind方法,它接受一个类名和一个参数为容器实例的闭包来获取实例
1 2 3
| $this->app->bind('\B', function ($app) { return new B(); });
|
另外,singleton方法与bind方法类似,不同的是singleton方法将类或接口绑定到只能解析一次的容器中,即单例。
在使用时,通过app的make方法解析,
1 2 3 4
| $api = $this->app->make('\B'); $api = $this->app->makeWith('\B' ['id' => 1]);
|
三. 服务提供者(Service Providers)
服务提供是laravel中十分重要的概念,在laravel生命周期和服务容器的实现中都有体现,也是实现Facade和合约(Contracts)的方法。
所有服务提供器都会继承 Illuminate\Support\ServiceProvider 类。大多数服务提供器都包含 register 和 boot 方法。在 register 方法中,只需要绑定类到服务容器中,在 root 方法中做视图相关的操作。
1.Service Providers绑定接口与实现
在Repositories文件夹下新建一个接口与实现类:
接口类:
1 2 3 4 5 6 7 8
| namespace App\Repositories; interface HouseInterface { public function selectAll(); public function findOne($id); }
|
实现类:
1 2 3 4 5 6 7 8 9 10 11 12
| namespace App\Repositories; class House implements HouseInterface { public function selectAll() { return ['all' => [1, 2, 3, 4, 5]]; } public function findOne($id) { return $id; } }
|
然后,在Provider中新建一个继承ServiceProvider的类HouseServiceProvider,在register方法中绑定接口与实现,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| namespace App\Providers; use Illuminate\Support\ServiceProvider; class HouseServiceProvider extends ServiceProvider { public function boot() { } public function register() { $this->app->bind( 'App\Repositories\HouseRepositoryInterface', 'App\Repositories\DbHouseRepository' ); } }
|
laravel中所有的Service Provider需要在config/app.php中providers数组中配置服务
1 2 3 4 5
| 'providers' => [ App\Providers\HouseServiceProvider::class, ]
|
这样就通过Server Provider实现了一个Contract,通过参数注入调用,
1 2 3 4 5 6 7 8 9 10 11 12 13
| namespace App\Http\ViewComposers; use App\Repositories\HouseInterface; class ProfileComposer { protected $house; public function __construct(HouseInterface $house) { $this->house = $house; } }
|
2.Service Providers实现视图合成器
新建类ComposerServiceProvider,继承ServiceProvider,在boot,调用View的composer方法,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| namespace App\Providers; use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; class ComposerServiceProvider extends ServiceProvider { public function boot() { View::composer( 'profile', 'App\Http\ViewComposers\ProfileComposer' ); } }
|
在config/app.php中providers数组中配置服务,
1 2 3 4 5
| 'providers' => [ App\Providers\ComposerServiceProvider::class, ]
|
注册了视图合成器,每次渲染 profile 视图时都会执行 ProfileComposer@compose 方法。定义视图合成器类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| namespace App\Http\ViewComposers; use Illuminate\View\View; use App\Repositories\HouseInterface; class ProfileComposer { protected $house; public function __construct(HouseInterface $house) { $this->house = $house; } public function compose(View $view) { $view->with('count', $this->house->findOne(2)); } }
|
需要注意的是,Service Provider中register方法先与boot方法执行。
四. Facades
Facades 是容器中类的静态代理,通过静态方法调用存放在容器中对象方法,表现形式为
1 2 3 4 5
| use Illuminate\Support\Facades\Cache; Route::get('/cache', function () { return Cache::get('key'); });
|
代码中Cache继承了Facade类,重写getFacadeAccessor方法
1 2 3 4 5 6 7
| class Cache extends Facade { protected static function getFacadeAccessor() { return 'cache'; } }
|
在laravel中,Illuminate\Support\Facades\Facade类的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public static function __callStatic($method, $args) { $instance = static::getFacadeRoot(); if (! $instance) { throw new RuntimeException('A facade root has not been set.'); } return $instance->$method(...$args); } public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); } protected static function getFacadeAccessor() { throw new RuntimeException('Facade does not implement getFacadeAccessor method.'); } protected static function resolveFacadeInstance($name) { if (is_object($name)) { return $name; } if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } return static::$resolvedInstance[$name] = static::$app[$name]; }
|
facades通过php魔术方法__callStatic实现。
五. Contracts
laravel中,使用Contracts 定义了接口,降低耦合性。通过Service Provider绑定接口到不同的实现。