当前位置: 首页 > 后端技术 > PHP

Laravel底层学习笔记04加载和启动ServiceProvider,事件(观察者模式)

时间:2023-03-29 20:49:53 PHP

参考资料:php:laravel底层核心代码分析加载和启动serviceProviderLaravelServiceProvider中启动方式和注册方式的区别phpartisan命令加载并启动ServiceProvider源码public/index.php$kernel=$app->make(Illuminate\Contracts\Http\Kernel::class);//1.Illuminate\Contracts\Http\Kernel::class是一个别名//2.$kernel是App\Http\Kernel//3的实例化对象。App\Http\Kernel::class继承src/Illuminate/Foundation/Http/Kernelvimsrc/Illuminate/Foundation/Http/Kernel.php//处理HTTP请求publicfunctionhandle($request)...vimvendor/symfony/http-foundation/Request.php//通过中间件和路由发送请求protectedfunctionsendRequestThroughRouter($request)...//引导应用程序进行HTTP请求publicfunctionbootstrap(){if(!$this->app->hasBeenBootstrapped()){$this->app->bootstrapWith($this->bootstrappers());}}vimvendor/laravel/framework/src/Illuminate/Foundation/Application.php/***运行给定的引导程序数组Kernel::class$this->bootstrappers**\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,*加载环境变量*\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,*加载配置文件*\Illuminate\Foundation\Bootstrap\HandleExceptions::class,*加载异常处理*\Illuminate\Foundation\Bootstrap\RegisterFacades::class,*注册外观模式*\Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,*设置控制台请求*\Illuminate\Foundation\Bootstrap\RegisterProviders::class,*注册提供者*\Illuminate\Foundation\Bootstrap\BootProviders::class,*启动Providers*/publicfunctionbootstrapWith(array$bootstrappers){$this->hasBeenBootstrapped=true;foreach($bootstrappersas$bootstrapper){$this['events']->fire('bootstrapping:'.$bootstrapper,[$this]);}//调用$bootstrapper实例中的bootstrap方法$this->make($bootstrapper)->bootstrap($this);//容器引用ArrayAccess//$this['events']等价于$this->make('events')$this['events']->fire('bootstrapped:'.$bootstrapper,[$this]);}}vim供应商/laravel/framework/src/Illuminate/Events/Dispatcher.php//启动事件并调用监听器publicfunctionfire($event,$payload=[],$halt=false){return$this->dispatch($event,$payload,$halt);}注册ProvidersvimIlluminate/Foundation/Bootstrap/RegisterProviders.phppublicfunctionbootstrap(Application$app){$app->registerConfiguredProviders();}vimIlluminate/Foundation/Application.php//所有配置的Providers加载框架publicfunctionregisterConfiguredProviders(){//$this->config['app.providers']是app/config的provider//将Illuminate开头的providers拆分成两个Collection数组$providers=Collection::make($this->config['app.providers'])//返回静态延迟加载->partition(function($provider){returnStr::startsWith($provider,'Illuminate\\');});//在Collection数组中引入第三方ServiceProvider$providers->splice(1,0,[$this->make(PackageManifest::class)->providers()]);//(新提供者erRepository($this,newFilesystem,$this->getCachedServicesPath()))->load($providers->collapse()->toArray());}vimsrc/Illuminate/Foundation/ProviderRepository.php//注册服务Providerspublicfunctionload(array$providers){//加载bootstrap/cache/services.php$manifest=$this->loadManifest();//判断是否重新编译$manifestif($this->shouldRecompile($manifest,$providers)){$manifest=$this->compileManifest($providers);}//为每个($manifest['when']as$provider=>$events)注册服务提供者($defer=true){$this->registerLoadEvents($provider,$events);}//注册一个非延迟加载的ServiceProvider(通过调用register方法)foreach($manifest['eager']as$provider){$this->app->register($provider);}//将延迟加载的ServiceProvider添加到容器的deferredServices数组中$this->app->addDeferredServices($manifest['deferred']);}StartProviderspublicfunctionboot(){if($this->;启动){返回;}$this->fireAppCallbacks($this->bootingCallbacks);array_walk($this->serviceProviders,function($p){$this->bootProvider($p);});$this->booted=true;$this->fireAppCallbacks($this->bootedCallbacks);}//调用serviceProviders中Provider实例的boot方法protectedfunctionbootProvider(ServiceProvider$provider){if(method_exists($provider,'boot')){return$this->call([$provider,'boot']);}}newself和newstaticnewself()返回self所在的类newstatic()返回调用者所在的类Father{publicfunctiongetSelf(){returnnewself();}publicfunctiongetStatic(){returnnewstatic();}}$f=newFather();echoget_class($f->getSelf());//Fatherechoget_class($f->getStatic());//FatherclassSonextendsFather{}$s=newSon();echoget_class($s->getSelf());//父choget_class($s->getStatic());//sonboot和register方法的区别register方法是必须的,boot方法不是register绑定方法服务到容器,框架会先调用所有provider的register方法,所有服务注册完成后,再调用每个服务的boot方法。所以在register方法中不能调用其他provider提供的服务,因为我们不能保证已经注册了其他服务。完全的。在引导方法中你可以做任何事情!延迟加载启用延迟加载vimFamilyServiceProvider.phpclassFamilyServiceProviderextendsDeferrableProvider{$defer=true;publicfunctionregister(){}publicfunctionproviders(){return['Family'];}}编译后的文件除外(优化操作的逆向)phpartisanclear-compiledcall//应用的make会调用deferServices数组中Family对应的实例app('Family')->test();//调用方法app('App\Service\Family\FamilyService')->test();//providers()方法等同于app('app')->bind('Family','App\Service\Family\FamilyService');源代码vimIlluminate/Foundation/Application.phppublicfunctionmake($abstract,array$parameters=[]){$abstract=$this->getAlias($abstract);如果(isset($this->deferredServices[$abstract])&&!isset($this->instances[$abstract])){$this->loadDeferredProvider($abstract);}}EventsandlistenersObserver模式Observer模式可以方便的创建一个对象来查看目标对象的状态,并提供与核心对象解耦的具体功能。当向由操作或状态更改激活的软件添加新的松散耦合功能时,应创建基于观察者模式的对象。模拟订单创建类时发送短信邮件非观察者模式order{publicfunctionadd(){$a=newMessage();$a->send();$b=newEmail();$b->发送();}}classMessage{publicfunctionsend(){echo'发送短信';}}classEmail{publicfunctionsend(){echo'发送邮件';}}$order=newOrder();$order->add();//发送短信和发送邮件观察者模式instance)===false){$this->instance[]=$observe;}}publicfunctiondel(Observe$observe){if($key=array_search($observe,$this->instance)!==false){unset($this->instance[$key]);}}publicfunctionnotify(){foreach($this->instanceas$observe){$observe->send();}}}//观察者接口Observe{functionsend();}classMessageimplementsObserve{publicfunctionsend(){echo'发送短信';}}classEmailimplementsObserve{publicfunctionsend(){echo'Sendemail';}}$order=newOrder();$order->add(newMessage());$order->add(newEmail());$order->notify();//send如果要发送钉钉短信提醒,只需要实现Observe接口类classDingTalkimplementsObserve{publicfunctionsend(){echo'发送钉钉提醒';}}$order=newOrder();$order->add(newDingTalk());$order->notify();//发送钉钉提醒创建事件和监听器创建事件和监听器phpartisanmake:eventEventTestphpartisanmake:listenerEventTestListenerphpartisanmake:listenerOtherListener注册事件和监听器vimapp/Providers/EventServiceProvider.php'App\Events\EventTest'=>['App\Listeners\EventListener','App\Listeners\OtherListener',],调用事件事件(newEventTest());