美文网首页
3.1 Laravel框架分析

3.1 Laravel框架分析

作者: MelodyOf流沙 | 来源:发表于2021-03-18 11:28 被阅读0次

    启动过程

    laravel的public/index.php文件.主要是理解Laravel初始的IOC实现

    <?php
    define('LARAVEL_START', microtime(true));
    
    /*
    加载PSR4命名空间
    */
    require __DIR__.'/../vendor/autoload.php';
    /*
    加载框架引导代码
    1.创建Application实例,此类是一个容器,是Laravel的DI(IOC)实现。
    2.加载一些基础的共享实例,例如Provider,路径变量,系统核心类的别名等
    */
    $app = require_once __DIR__.'/../bootstrap/app.php';
    
    /*
    使用框架Kernel处理用户的请求,并返回结果给用户
    1.获取到kernel实例
    2.解析Request请求
    3.加载框架基础的服务,变量,配置
    4.dispatchRouter,分发路由,执行相应的请求
    5.获取到执行完的结果返回Request请求
    */
    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    $response->send();
    //执行结束,终止脚本
    $kernel->terminate($request, $response);
    
    

    Facade

    先分析下Facade的注册过程,也就是框架启动时,如何把config文件中注册的facade注册到系统中

    $app = require_once __DIR__.'/../bootstrap/app.php';
    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    /*
    index.php中,ioc容器建立之后执行Kernel的handle方法
    */
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    $response->send();
    $kernel->terminate($request, $response);
    
    public function handle($request)
        {
            try {
                $request->enableHttpMethodParameterOverride();
                //此方法sendRequestThroughRouter中会执行相应的Provider以及Facade
                $response = $this->sendRequestThroughRouter($request);
            } catch (Throwable $e) {
                $this->reportException($e);
                $response = $this->renderException($request, $e);
            }
            $this->app['events']->dispatch(
                new RequestHandled($request, $response)
            );
            return $response;
        }
    protected function sendRequestThroughRouter($request)
        {
            $this->app->instance('request', $request);
    
            Facade::clearResolvedInstance('request');
            //进行bootstrap方法
            $this->bootstrap();
    
            return (new Pipeline($this->app))
                        ->send($request)
                        ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                        ->then($this->dispatchToRouter());
        }
    public function bootstrap()
        {
            if (! $this->app->hasBeenBootstrapped()) {
                //执行bootstrapWith
                //    protected $bootstrappers = [
    //        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    //        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    //        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    //        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    //        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    //        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    //    ];
                $this->app->bootstrapWith($this->bootstrappers());
            }
        }
    

    回到Application类中实现的bootstrapWith方法

    public function bootstrapWith(array $bootstrappers)
        {
            $this->hasBeenBootstrapped = true;
    
            foreach ($bootstrappers as $bootstrapper) {
                $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);
                //创建实例,并执行实例中的bootstrap方法.
                $this->make($bootstrapper)->bootstrap($this);
                $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
            }
        }
    

    之前bootstrapper中有RegisterFacades类,我们看下RegisterFacades中实现的bootstrap方法

    public function bootstrap(Application $app)
        {
            Facade::clearResolvedInstances();
            Facade::setFacadeApplication($app);
            //获取app.aliases配置文件中的数据信息,并执行register方法
            AliasLoader::getInstance(array_merge(
                $app->make('config')->get('app.aliases', []),
                $app->make(PackageManifest::class)->aliases()
            ))->register();
        }
    //获取到AliasLoader类的实例,执行register去注册spl_autoload_register命名空间
    public function register()
        {
            if (! $this->registered) {
                $this->prependToLoaderStack();
    
                $this->registered = true;
            }
        }
    protected function prependToLoaderStack()
        {
            spl_autoload_register([$this, 'load'], true, true);
        }
    

    至此Facade的注册已经完成,接下来我们分析Cache
    我们拿Redis的Facade来举例

    class Cache extends Facade
    {
      //复写getFacadeAccessor方法,返回的字符串cache就是注册在ioc中所对应的名字。此方法为必须复写的方法,不复写会报错
        protected static function getFacadeAccessor()
        {
            return 'cache';
        }
    }
    

    接下来我们看下Facade类,比如当我们执行Cache::set时的流程

    //Facade中实现了魔术方法__callStatic,当发现类使用静态调用时,执行此方法
    public static function __callStatic($method, $args)
        {
            //获取对应的facade实例
            $instance = static::getFacadeRoot();
            if (! $instance) {
                throw new RuntimeException('A facade root has not been set.');
            }
            //使用实例所对应的方法
            return $instance->$method(...$args);
        }
    //分析getFacadeRoot方法
    public static function getFacadeRoot()
        {   //getFacadeAccessor前面子类已经复写了
            return static::resolveFacadeInstance(static::getFacadeAccessor());
        }
    protected static function resolveFacadeInstance($name)
        {
            if (is_object($name)) {
                return $name;
            }
    
            if (isset(static::$resolvedInstance[$name])) {
                return static::$resolvedInstance[$name];
            }
    
            if (static::$app) {
                //因为Application实现了ArrayAccess接口,所以可以直接$app['']
    数组方式进行获取实例
                 return static::$resolvedInstance[$name] = static::$app[$name];
            }
        }
        //ArrayAccess接口的实现,其实也是去make获取实例
        public function offsetGet($key)
        {
            return $this->make($key);
        }
    

    Route

    看路由解析过程
    进入Kernel文件对handle方法的实现

    public function handle($request)
        {
            try {
                $request->enableHttpMethodParameterOverride();
    
                $response = $this->sendRequestThroughRouter($request);
            } catch (Throwable $e) {
                $this->reportException($e);
    
                $response = $this->renderException($request, $e);
            }
    
            $this->app['events']->dispatch(
                new RequestHandled($request, $response)
            );
    
            return $response;
        }
    
    protected function sendRequestThroughRouter($request)
        {
            $this->app->instance('request', $request);
    
            Facade::clearResolvedInstance('request');
    
            $this->bootstrap();
    
            return (new Pipeline($this->app))
                        ->send($request)
                        ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                        ->then($this->dispatchToRouter());
        }
    protected function dispatchToRouter()
        {
            return function ($request) {
                $this->app->instance('request', $request);
    
                return $this->router->dispatch($request);
            };
        }
    public function dispatch(Request $request)
        {
            $this->currentRequest = $request;
    
            return $this->dispatchToRoute($request);
        }
    public function dispatchToRoute(Request $request)
        {
            return $this->runRoute($request, $this->findRoute($request));
        }
    protected function findRoute($request)
        {
            $this->current = $route = $this->routes->match($request);
    
            $this->container->instance(Route::class, $route);
    
            return $route;
        }
    protected function runRoute(Request $request, Route $route)
        {
            $request->setRouteResolver(function () use ($route) {
                return $route;
            });
    
            $this->events->dispatch(new RouteMatched($route, $request));
    
            return $this->prepareResponse($request,
                $this->runRouteWithinStack($route, $request)
            );
        }
    protected function runRouteWithinStack(Route $route, Request $request)
        {
            $shouldSkipMiddleware = $this->container->bound('middleware.disable') &&
                                    $this->container->make('middleware.disable') === true;
    
            $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
    
            return (new Pipeline($this->container))
                            ->send($request)
                            ->through($middleware)
                            ->then(function ($request) use ($route) {
                                return $this->prepareResponse(
                                    $request, $route->run()
                                );
                            });
        }
    

    相关文章

      网友评论

          本文标题:3.1 Laravel框架分析

          本文链接:https://www.haomeiwen.com/subject/pekdcltx.html