我是靠谱客的博主 妩媚煎蛋,最近开发中收集的这篇文章主要介绍Laravel生命周期学习一,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

生命周期

  • index.php

1.1 检测是否处于维护模式

if (file_exists(__DIR__.'/../storage/framework/maintenance.php')) {
    require __DIR__.'/../storage/framework/maintenance.php';
}

1.2 加载composer自动加载文件

require __DIR__.'/../vendor/autoload.php';

1.3 加载初始化容器

$app = require_once __DIR__.'/../bootstrap/app.php';

1.3.1 初始化__construct()

class Application extends Container implements ApplicationContract, CachesConfiguration, CachesRoutes, HttpKernelInterface
{
    public function __construct($basePath = null)
    {
        if ($basePath) {
            $this->setBasePath($basePath);
        }

        $this->registerBaseBindings();
        $this->registerBaseServiceProviders();
        $this->registerCoreContainerAliases();
    }
}

1.3.1.1 设置项目的根目录路径

    public function setBasePath($basePath)
    {
        $this->basePath = rtrim($basePath, '/');

        $this->bindPathsInContainer();

        return $this;
    }

    protected function bindPathsInContainer()
    {
        //项目的app path 
        $this->instance('path', $this->path());
        //根目录
        $this->instance('path.base', $this->basePath());
        //多语言翻译目录
        $this->instance('path.lang', $this->langPath());
        //config 配置文件路径
        $this->instance('path.config', $this->configPath());
        //public 目录路径
        $this->instance('path.public', $this->publicPath());
        //storage 目录路径
        $this->instance('path.storage', $this->storagePath());
        //数据库迁移文件路径
        $this->instance('path.database', $this->databasePath());
        //资源文件路径
        $this->instance('path.resources', $this->resourcePath());
        //bootstrap 文件路径
        $this->instance('path.bootstrap', $this->bootstrapPath());
    }

1.3.1.2 注册基本绑定到容器

    protected function registerBaseBindings()
    {
        //把当前实例初始给类常量 $instance
        static::setInstance($this);
        
        //把当前实例注册到app这个字符串
        $this->instance('app', $this);
    
        //把当前实例注册到 Container
        $this->instance(Container::class, $this);
        
        //单利注册渲染前端打包渲染文件
        $this->singleton(Mix::class);
        
        //单利注册 composer 包相关的类到容器
        $this->singleton(PackageManifest::class, function () {
            return new PackageManifest(
                new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
            );
        });
    }

1.3.1.3 注册基础服务

    protected function registerBaseServiceProviders()
    {
        //注册事件监听
        $this->register(new EventServiceProvider($this));
        //注册日志服务
        $this->register(new LogServiceProvider($this));
        //注册路由服务
        $this->register(new RoutingServiceProvider($this));
        
        register();
        // 判断 $this->getProvider($provider)当前容器中是否注册了这个服务,有直接返回
        // 判断传递进来的第一个参数是否是一个字符串,如果是就new当前这个服务提供者
        if (is_string($provider)) {
                    $provider = $this->resolveProvider($provider);
                }
        //调用当前传递进来的服务提供者的register()方法
        $provider->register();
        //判断当前服务提供者是否具有bindings属性,有就循环它,并且使用容器的bind方法绑定
        if (property_exists($provider, 'bindings')) {
                    foreach ($provider->bindings as $key => $value) {
                        $this->bind($key, $value);
                    }
                }
        //判断当前服务提供者是否具有singletons属性,有就循环它,并且使用容器的singleton方法绑定
        if (property_exists($provider, 'singletons')) {
                    foreach ($provider->singletons as $key => $value) {
                        $this->singleton($key, $value);
                    }
                }
        //将当前传递过来的服务提供者放入容器的$serviceProviders数组,并且使用$loadedProviders数组存储当前服务提供者的类名,并且标记(value)为true
        $this->serviceProviders[] = $provider;
        
        $this->loadedProviders[get_class($provider)] = true;
        
        //判断当前的容器是否已经启动,如果启动了,就判断当前传递过来的服务提供者中是否具有boot方法,有就调用
        if ($this->isBooted()) {
                    $this->bootProvider($provider);
                }
        $provider->callBootingCallbacks();

        if (method_exists($provider, 'boot')) {
            $this->call([$provider, 'boot']);
        }

        $provider->callBootedCallbacks();
        //最后返回传递过来的服务提供者
    }

1.3.1.4 给当前容器中的核心类绑定别名放入数组$aliases $abstractAliases

//别名当作数组的值,核心类当作当前数组的值
$this->aliases[$alias] = $abstract;

//核心类当作二维数组中的键,别名放入二维数组中
$this->abstractAliases[$abstract][] = $alias;

1.4 单利注册http内核

$app->singleton(
    IlluminateContractsHttpKernel::class,
    AppHttpKernel::class
);

1.5 单利注册命令行内核

$app->singleton(
    IlluminateContractsConsoleKernel::class,
    AppConsoleKernel::class
);

1.6 单利注册错误处理内核

$app->singleton(
    IlluminateContractsDebugExceptionHandler::class,
    AppExceptionsHandler::class
);
  • 容器的单利注册方法 singleton()

实质是调用容器的bind()方法,$this->bind($abstract, $concrete, true);传递的第三个参数为true即代表单利注册

第一步是先去容器数组中删除当前注册的服务unset($this->instances[$abstract], $this->aliases[$abstract]);

第二步判断,当前传递过来的参数二是否为null也就代表在使用singleton()方法的时候,可以只传递第一个参数,然后容器方法会做判断,如果没有传递第二个
参数,那么就会把第一个参数赋值给第二个参数

if (is_null($concrete)) {
            $concrete = $abstract;
        }

第三步判断当前传递的第二个需要绑定的类是否是一个匿名类,如果是匿名类就直接注册到数组$bindings$this->bindings[$abstract] = compact('concrete', 'shared');
如果不是一个匿名类,就进入判断中

if (! $concrete instanceof Closure) {
            if (! is_string($concrete)) {
                throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');
            }

            $concrete = $this->getClosure($abstract, $concrete);
        }

调用这个方法getClosure()返回一个匿名类,绑定到数组中$bindings

第四步判断当前容器中是否已经绑定了这个抽象类,如果是,进入if判断

$instance = $this->make($abstract);

foreach ($this->getReboundCallbacks($abstract) as $callback) {
    call_user_func($callback, $this, $instance);
}

1.7 实例化IlluminateContractsHttpKernel类,核心http请求内核,并调用

    protected function syncMiddlewareToRouter()
    {
        //把当前的全局中间件赋值给路由的全局中间件组
        //IlluminateCookieMiddlewareEncryptCookies::class, cookie加密
        //IlluminateSessionMiddlewareStartSession::class, 开启session
        //IlluminateViewMiddlewareShareErrorsFromSession::class,
        //IlluminateContractsAuthMiddlewareAuthenticatesRequests::class,
        //IlluminateRoutingMiddlewareThrottleRequests::class,
        //IlluminateSessionMiddlewareAuthenticateSession::class,
        //IlluminateRoutingMiddlewareSubstituteBindings::class,
        //IlluminateAuthMiddlewareAuthorize::class,
        $this->router->middlewarePriority = $this->middlewarePriority;
            
        //把路由组
        foreach ($this->middlewareGroups as $key => $middleware) {
            //添加到路由类的数组$middlewareGroups中
            $this->router->middlewareGroup($key, $middleware);
        }

        foreach ($this->routeMiddleware as $key => $middleware) {
            //添加到路由类的数组$middleware
            $this->router->aliasMiddleware($key, $middleware);
        }
    }

1.7.1 调用 handle()

第一步: $response = $this->sendRequestThroughRouter($request);

第二步: $this->bootstrap();

    public function bootstrap()
    {
        if (! $this->app->hasBeenBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }

第三步:


    protected $bootstrappers = [
            IlluminateFoundationBootstrapLoadEnvironmentVariables::class,
            IlluminateFoundationBootstrapLoadConfiguration::class,
            IlluminateFoundationBootstrapHandleExceptions::class,
            IlluminateFoundationBootstrapRegisterFacades::class,
            IlluminateFoundationBootstrapRegisterProviders::class,
            IlluminateFoundationBootstrapBootProviders::class,
        ];
    protected function bootstrappers()
    {
        return $this->bootstrappers;
    }

第四步:

    public function bootstrapWith(array $bootstrappers)
    {
        $this->hasBeenBootstrapped = true;

        foreach ($bootstrappers as $bootstrapper) {
            $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);

            $this->make($bootstrapper)->bootstrap($this);

            $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
        }
    }

第五步:实例化数组$bootstrappers中的类,并调用各自的bootstrap()方法

    //LoadEnvironmentVariables
    public function bootstrap(Application $app)
    {
        if ($app->configurationIsCached()) {
            return;
        }

        $this->checkForSpecificEnvironmentFile($app);

        try {
            $this->createDotenv($app)->safeLoad();
        } catch (InvalidFileException $e) {
            $this->writeErrorAndDie($e);
        }
    }
    
    //LoadConfiguration 加载config 文件的配置
        public function bootstrap(Application $app)
        {
            $items = [];
    
            // First we will see if we have a cache configuration file. If we do, we'll load
            // the configuration items from that file so that it is very quick. Otherwise
            // we will need to spin through every configuration file and load them all.
            if (is_file($cached = $app->getCachedConfigPath())) {
                $items = require $cached;
    
                $loadedFromCache = true;
            }
    
            // Next we will spin through all of the configuration files in the configuration
            // directory and load each one into the repository. This will make all of the
            // options available to the developer for use in various parts of this app.
            $app->instance('config', $config = new Repository($items));
    
            if (! isset($loadedFromCache)) {
                $this->loadConfigurationFiles($app, $config);
            }
    
            // Finally, we will set the application's environment based on the configuration
            // values that were loaded. We will pass a callback which will be used to get
            // the environment in a web context where an "--env" switch is not present.
            $app->detectEnvironment(function () use ($config) {
                return $config->get('app.env', 'production');
            });
    
            date_default_timezone_set($config->get('app.timezone', 'UTC'));
    
            mb_internal_encoding('UTF-8');
        }

    //HandleExceptions 注册异常处理类
    public function bootstrap(Application $app)
    {
        self::$reservedMemory = str_repeat('x', 10240);

        $this->app = $app;

        error_reporting(-1);

        set_error_handler([$this, 'handleError']);

        set_exception_handler([$this, 'handleException']);

        register_shutdown_function([$this, 'handleShutdown']);

        if (! $app->environment('testing')) {
            ini_set('display_errors', 'Off');
        }
    }
    //RegisterFacades 注册门脸类 config.app.aliases类实现访问自动加载
    public function bootstrap(Application $app)
    {
        Facade::clearResolvedInstances();

        Facade::setFacadeApplication($app);

        AliasLoader::getInstance(array_merge(
            $app->make('config')->get('app.aliases', []),
            $app->make(PackageManifest::class)->aliases()
        ))->register();
    }
    //RegisterProviders 实例化config.app.providers数组中的类
    public function bootstrap(Application $app)
    {
        $app->registerConfiguredProviders();
    }
    //BootProviders 运行所有已注册到容器中类的boot方法
    public function bootstrap(Application $app)
    {
        $app->boot();
    }

第六步:实例化一个管道类 Pipline()传递当前的容器给__construct()方法,赋值给管道类的$this->container变量
调用管道类的send()方法并把当前的请求$request当作参数传递进来,赋值给管道类的$this->passable变量
链式调用管道类的through()方法

(new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
  • 最重要之dispatchToRouter()方法,再次调用IlluminateRoutingRouter类的dispatch()方法
protected function dispatchToRouter()
    {
        return function ($request) {
            $this->app->instance('request', $request);

            return $this->router->dispatch($request);
        };
    }

调用方法dispatch($request)(),把当前的request类赋值给$currentRequest变量,接着调用dispatchToRoute()方法

    public function dispatch(Request $request)
    {
        $this->currentRequest = $request;

        return $this->dispatchToRoute($request);
    }

方法dispatchToRoute(),调用findRoute()方法,request请求类当作参数

    public function dispatchToRoute(Request $request)
    {
        return $this->runRoute($request, $this->findRoute($request));
    }

方法 findRoute($request),调用match()方法,$request请求类当作参数

    protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);
        
        $this->container->instance(Route::class, $route);

        return $route;
    }

方法 match($request),首先得到当前的请求方法,get post head ...IlluminateRoutingRouteCollection路由集合方法中,再次调用
get()方法,拿到当前get或者post等等提交的所有路由信息,是一个请求方法为键的数组集合

    public function match(Request $request)
    {
        $routes = $this->get($request->getMethod());

        // First, we will see if we can find a matching route for this current request
        // method. If we can, great, we can just return it so that it can be called
        // by the consumer. Otherwise we will check for routes with another verb.
        $route = $this->matchAgainstRoutes($routes, $request);

        return $this->handleMatchedRoute($request, $route);
    }

再次调用matchAgainstRoutes()方法,第一个参数就是当前请求方法的数组,第二个参数就是请求类,匹配得到当前的路由类

    protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true)
    {
        [$fallbacks, $routes] = collect($routes)->partition(function ($route) {
            return $route->isFallback;
        });

        return $routes->merge($fallbacks)->first(function (Route $route) use ($request, $includingMethod) {
            return $route->matches($request, $includingMethod);
        });
    }

调用handleMatchedRoute()方法

    protected function handleMatchedRoute(Request $request, $route)
    {
        if (! is_null($route)) {
            return $route->bind($request);
        }

        // If no route was found we will now check if a matching route is specified by
        // another HTTP verb. If it is we will need to throw a MethodNotAllowed and
        // inform the user agent of which HTTP verb it should use for this route.
        $others = $this->checkForAlternateVerbs($request);

        if (count($others) > 0) {
            return $this->getRouteForMethods($request, $others);
        }

        throw new NotFoundHttpException;
    }

最后

以上就是妩媚煎蛋为你收集整理的Laravel生命周期学习一的全部内容,希望文章能够帮你解决Laravel生命周期学习一所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部