加载并启动ServiceProvider
源码
代码语言:javascript复制public/index.php
$kernel = $app->make(IlluminateContractsHttpKernel::class);
//1. IlluminateContractsHttpKernel::class 是别名
//2. $kernel是AppHttpKernel的实例化对象
//3. AppHttpKernel::class继承src/Illuminate/Foundation/Http/Kernel
代码语言:javascript复制vim src/Illuminate/Foundation/Http/Kernel.php
//处理HTTP请求
public function handle($request) ...
代码语言:javascript复制vim vendor/symfony/http-foundation/Request.php
//发送请求穿过中间件和路由
protected function sendRequestThroughRouter($request) ...
//为HTTP请求引导应用程序
public function bootstrap()
{
if (! $this->app->hasBeenBootstrapped()) {
$this->app->bootstrapWith($this->bootstrappers());
}
}
代码语言:javascript复制vim vendor/laravel/framework/src/Illuminate/Foundation/Application.php
/**
* 运行给定的引导类数组 Kernel::class $this->bootstrappers
*
* IlluminateFoundationBootstrapLoadEnvironmentVariables::class,
* 加载环境变量
* IlluminateFoundationBootstrapLoadConfiguration::class,
* 加载配置文件
* IlluminateFoundationBootstrapHandleExceptions::class,
* 加载异常处理
* IlluminateFoundationBootstrapRegisterFacades::class,
* 注册门面模式
* IlluminateFoundationBootstrapSetRequestForConsole::class,
* 设置Console请求
* IlluminateFoundationBootstrapRegisterProviders::class,
* 注册Providers
* IlluminateFoundationBootstrapBootProviders::class,
* 启动Providers
*/
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
foreach ($bootstrappers as $bootstrapper) {
$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
//调用$bootstrapper实例中的bootstrap方法
$this->make($bootstrapper)->bootstrap($this);
//Container引用了ArrayAccess
//$this['events']相当于$this->make('events')
$this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);
}
}
代码语言:javascript复制vim vendor/laravel/framework/src/Illuminate/Events/Dispatcher.php
//启动事件并调用监听者
public function fire($event, $payload = [], $halt = false)
{
return $this->dispatch($event, $payload, $halt);
}
注册Providers
代码语言:javascript复制vim Illuminate/Foundation/Bootstrap/RegisterProviders.php
public function bootstrap(Application $app)
{
$app->registerConfiguredProviders();
}
代码语言:javascript复制vim Illuminate/Foundation/Application.php
// 将所有配置的providers载入框架
public function registerConfiguredProviders(){
//$this->config['app.providers']是app/config的providers
//将是否以Illuminate开头的providers分割到两个Collection数组中
$providers = Collection::make($this->config['app.providers'])//return static 延时加载
->partition(function ($provider) {
return Str::startsWith($provider, 'Illuminate\');
});
//引入第三方的Service Providers加入Collection数组中
$providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
//
(new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
->load($providers->collapse()->toArray());
}
代码语言:javascript复制vim src/Illuminate/Foundation/ProviderRepository.php
//注册Service Providers
public function load(array $providers)
{
//加载bootstrap/cache/services.php
$manifest = $this->loadManifest();
//判断是否需要重新编译$manifest
if ($this->shouldRecompile($manifest, $providers)) {
$manifest = $this->compileManifest($providers);
}
//注册需要延迟加载的Serivice Provider($defer=true)
foreach ($manifest['when'] as $provider => $events) {
$this->registerLoadEvents($provider, $events);
}
//注册非延迟加载的Serivice Provider(通过调用register方法)
foreach ($manifest['eager'] as $provider) {
$this->app->register($provider);
}
//将延迟加载的Serivice Provider加入容器的deferredServices数组
$this->app->addDeferredServices($manifest['deferred']);
}
启动Providers
代码语言:javascript复制public function boot()
{
if ($this->booted) {
return;
}
$this->fireAppCallbacks($this->bootingCallbacks);
array_walk($this->serviceProviders, function ($p) {
$this->bootProvider($p);
});
$this->booted = true;
$this->fireAppCallbacks($this->bootedCallbacks);
}
//调用serviceProviders中Provider实例的boot方法
protected function bootProvider(ServiceProvider $provider)
{
if (method_exists($provider, 'boot')) {
return $this->call([$provider, 'boot']);
}
}
new self 和new static
代码语言:javascript复制new self() 返回的是self所在类 new static() 返回调用者所在类
class Father{
public function getSelf(){
return new self();
}
public function getStatic(){
return new static();
}
}
$f = new Father();
echo get_class($f->getSelf());//Father
echo get_class($f->getStatic());//Father
class Son extends Father{
}
$s = new Son();
echo get_class($s->getSelf());//Father
echo get_class($s->getStatic());//Son
boot和register方法的区别
代码语言:javascript复制register方法是必须的,boot方法不是
register 方法用于绑定服务到容器,框架会先调用所有 provider 的 register 方法,等所有服务都注册完毕再去调用每一个服务的 boot 方法。
所以不能在 register 方法里面调用其他 provider 提供的服务,因为我们无法保证其他服务已经注册完毕。
而在 boot 方法里面你可以干任何事情!
延迟加载
开启延迟加载
代码语言:javascript复制vim FamilyServiceProvider.php
class FamilyServiceProvider extends DeferrableProvider{
$defer = true;
public function register(){
}
public function providers(){
return ['Family'];
}
}
代码语言:javascript复制除编译生成的文件(optimize的反向操作)
php artisan clear-compiled
代码语言:javascript复制调用
//Application的make会调用deferServices数组中Family对应的实例
app('Family')->test();
//没有实现providers()时的调用方法
app('AppServiceFamilyFamilyService')->test();
//providers()方法等价于
app('app')->bind('Family','AppServiceFamilyFamilyService');
源码
代码语言:javascript复制vim Illuminate/Foundation/Application.php
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($abstract);
if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
$this->loadDeferredProvider($abstract);
}
}
事件和监听者
观察者模式
观察者模式能够便利的创建查看目标对象状态的对象,并且提供与核心对象非耦合的指定性功能。 为软件添加由某个动作或状态变化激活的,但是松散耦合的新功能时,应当创建基于观察者模式的对象。
模拟创建订单时发送短信邮件
非观察者模式
代码语言:javascript复制class order{
public function add(){
$a = new Message();$a->send();
$b = new Email();$b->send();
}
}
class Message{
public function send(){
echo '发送短信';
}
}
class Email{
public function send(){
echo '发送邮件';
}
}
$order = new Order();
$order->add();//发送短信发送邮件
观察者模式
代码语言:javascript复制<?php
//被观察者接口
interface Observable{
function add(Observe $observe);//新增观察者
function del(Observe $observe);//删除观察者
}
class order implements Observable{
private $instance = array();
public function add(Observe $observe){
if(array_search($observe, $this->instance) === false){
$this->instance[] = $observe;
}
}
public function del(Observe $observe){
if($key = array_search($observe, $this->instance) !== false){
unset($this->instance[$key]);
}
}
public function notify(){
foreach ($this->instance as $observe){
$observe->send();
}
}
}
//观察者
interface Observe{
function send();
}
class Message implements Observe{
public function send(){
echo '发送短信';
}
}
class Email implements Observe{
public function send(){
echo '发送邮件';
}
}
$order = new Order();
$order->add(new Message());
$order->add(new Email());
$order->notify();//发送短信发送邮件
如果再想发送钉钉提醒,则只需要实现Observe接口类即可
代码语言:javascript复制class DingTalk implements Observe{
public function send(){
echo '发送钉钉提醒';
}
}
$order = new Order();
$order->add(new DingTalk());
$order->notify();//发送钉钉提醒
创建事件和监听者
创建事件和监听者
代码语言:javascript复制php artisan make:event EventTest
php artisan make:listener EventTestListener
php artisan make:listener OtherListener
注册事件和监听者
代码语言:javascript复制vim app/Providers/EventServiceProvider.php
'AppEventsEventTest' => [
'AppListenersEventListener',
'AppListenersOtherListener',
],
调用事件
代码语言:javascript复制event(new EventTest());