3.1 Laravel框架分析

启动过程

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()
                            );
                        });
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容