Home> PHP Framework> Laravel> body text

Let's talk about Laravel's life cycle

WBOY
Release: 2022-04-25 12:04:13
forward
3197 people have browsed it

This article brings you relevant knowledge aboutlaravel, which mainly introduces issues related to the life cycle of Laravel. The life cycle of Laravel starts from public\index.php and ends with public\ index.php ends, I hope this helps everyone.

Let's talk about Laravel's life cycle

[Related recommendations:laravel video tutorial]

Laravel’s life cycle A

Everything in the world All have a life cycle. When we use any tool, we need to understand its working principle, so that it will be easy to use. The same is true for application development. Once you understand its principles, you will be able to use it with ease.

Before understanding the life cycle of Laravel, let us first review the life cycle of PHP.

PHP’s operating mode

The two operating modes of PHP are WEB mode and CLI mode.

When we type the php command in the terminal, we are using the CLI mode.

When using Nginx or another web server as the host to handle an incoming request, the WEB mode is used.

Life cycle of PHP

When we request a php file, PHP will undergo 5 stages of life cycle switching in order to complete the request:

  • 1 Module initialization (MINIT), that is, calling the extended initialization function specified in php.ini to perform initialization work, such as mysql extension.

  • #2 Request initialization (RINIT), that is, initialize the symbol table with variable names and variable value contents required to execute this script, such as the $_SESSION variable.

  • #3 Execute the PHP script.

  • #4 After the request processing is completed (Request Shutdown), call the RSHUTDOWN method of each module in sequence, and call the unset function on each variable, such as unset $_SESSION variable.

  • 5 Shut down the module (Module Shutdown). PHP calls the MSHUTDOWN method of each extension. This is the last opportunity for each module to release memory. This means there is no next request.

WEB mode is very similar to CLI (command line) mode, the difference is:

CLI mode It will go through a complete 5 cycles every time the script is executed, because there will be no next request after your script is executed;

WEB mode in order to cope with Concurrency may use multi-threading, so life cycles 1 and 5 may be executed only once, and life cycles 2-4 will be repeated when the next request comes, thus saving the overhead caused by system module initialization.

#It can be seen that the PHP life cycle is very symmetrical. Having said all this, it is to locate where Laravel is running. Yes, Laravel only runs in the third stage:

Lets talk about Laravels life cycle

Function

Understand these, you can optimize your Laravel code and have a deeper understanding of Laravel's singleton (single case).

At least you know that every time a request ends, PHP variables will be unset, and Laravel's singleton is only a singleton during a certain request;

Your static variables in Laravel cannot be shared between multiple requests, because they will be unset at the end of each request.

Understanding these concepts is the first and most critical step in writing high-quality code. So remember, PHP is a scripting language, and all variables will only take effect in this request and will be reset on the next request, unlike Java static variables that have global effects.

Laravel’s life cycle

Overview

Laravel’s life cycle starts from public\index.php and ends with public\ index.php ends.

Lets talk about Laravels life cycle

Request process

The following is the full source code of public\index.php, more specifically It can be divided into four steps:

make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); $response->send(); $kernel->terminate($request, $response);
Copy after login

The following is a detailed explanation of the four steps: composer automatically loads the required classes

  • 1 文件载入composer生成的自动加载设置,包括所有你 composer require的依赖。
  • 2 生成容器 Container,Application实例,并向容器注册核心组件(HttpKernel,ConsoleKernel ,ExceptionHandler)(对应代码2,容器很重要,后面详细讲解)。
  • 3 处理请求,生成并发送响应(对应代码3,毫不夸张的说,你99%的代码都运行在这个小小的handle 方法里面)。
  • 4 请求结束,进行回调(对应代码4,还记得可终止中间件吗?没错,就是在这里回调的)。

Lets talk about Laravels life cycle

Laravel 的请求步骤

第一步:注册加载composer自动生成的class loader
就是加载初始化第三方依赖。

第二步:生成容器 Container
并向容器注册核心组件,是从 bootstrap/app.php 脚本获取 Laravel 应用实例,

第三步:这一步是重点,处理请求,并生成发送响应。
请求被发送到 HTTP 内核或 Console 内核,这取决于进入应用的请求类型。

取决于是通过浏览器请求还是通过控制台请求。这里我们主要是通过浏览器请求。

HTTP 内核继承自 Illuminate\Foundation\Http\Kernel 类,该类定义了一个 bootstrappers 数组,这个数组中的类在请求被执行前运行,这些 bootstrappers 配置了错误处理、日志、检测应用环境以及其它在请求被处理前需要执行的任务。

protected $bootstrappers = [ //注册系统环境配置 (.env) 'Illuminate\Foundation\Bootstrap\DetectEnvironment', //注册系统配置(config) 'Illuminate\Foundation\Bootstrap\LoadConfiguration', //注册日志配置 'Illuminate\Foundation\Bootstrap\ConfigureLogging', //注册异常处理 'Illuminate\Foundation\Bootstrap\HandleExceptions', //注册服务容器的门面,Facade 是个提供从容器访问对象的类。 'Illuminate\Foundation\Bootstrap\RegisterFacades', //注册服务提供者 'Illuminate\Foundation\Bootstrap\RegisterProviders', //注册服务提供者 `boot` 'Illuminate\Foundation\Bootstrap\BootProviders', ];
Copy after login

Lets talk about Laravels life cycle

Laravel的生命周期 B

Lets talk about Laravels life cycle

laravel/public/index.php

/** * laravel的启动时间 */ define('LARAVEL_START', microtime(true)); /** * 加载项目依赖。 * 现代PHP依赖于Composer包管理器,入口文件通过引入由Composer包管理器。 * 自动生成的类加载程序,可以轻松注册并加载所依赖的第三方组件库。 */ require __DIR__.'/../vendor/autoload.php'; /** * 创建laravel应用实例。 */ $app = require_once __DIR__.'/../bootstrap/app.php'; // 接受请求并响应 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); // 结束请求,进行回调 $response->send(); // 终止程序 $kernel->terminate($request, $response);
Copy after login

laravel/boostrap/app.php

# 第一部分:创建应用实例 $app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') ); # 第二部分:完成内核绑定 $app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class ); $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class ); $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class ); return $app;
Copy after login

laravel\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php

class Kernel implements KernelContract { 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, // 注册服务提供者boot ]; // 处理请求 public function handle($request) { try { $request->enableHttpMethodParameterOverride(); $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); $response = $this->renderException($request, $e); } catch (Throwable $e) { $this->reportException($e = new FatalThrowableError($e)); $response = $this->renderException($request, $e); } $this->app['events']->dispatch( new Events\RequestHandled($request, $response) ); return $response; } protected function sendRequestThroughRouter($request) { # 一、将$request实例注册到APP容器 $this->app->instance('request', $request); # 二、清除之前的$request实例缓存 Facade::clearResolvedInstance('request'); # 三、启动引导程序 $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()) { $this->app->bootstrapWith($this->bootstrappers()); } } # 路由分发 protected function dispatchToRouter() { return function ($request) { $this->app->instance('request', $request); return $this->router->dispatch($request); }; } # 终止程序 public function terminate($request, $response) { $this->terminateMiddleware($request, $response); $this->app->terminate(); }
Copy after login

Laravel 服务容器模块

简介

服务容器是一个用于管理类依赖和执行依赖注入的强大工具。是整个框架的核心;

几乎所有的服务容器绑定都是在服务提供者中完成。

框架调用分析

在框架直接生成服务容器的只有一处,在bootstrap/app.php,通过require引用会返回服务容器实例。通过require引用有两处,一处是public/index.php,服务器访问的入口;另一处是tests/CreatesApplication.php,是单元测试的入口;

如果想在项目各处中调用,可以调用$app = Illuminate\Container\Container::getInstance()或者全局帮助函数app()获取服务容器实例(也就是Illuminate\Foundation/Application实例);

Illuminate\Foundation/Application是对Illuminate\Container\Container的又一层封装;

Application初始化

那么实例化Illuminate\Foundation/Application时,做了什么呢?

第一步,设置应用的根目录,并同时注册核心目录到服务容器中;核心的目录有以下

  • path: The location of the directoryapp

  • #path.base: The location of the project root directory

  • path.lang:The location of directory resources/lang

  • path.config:Directory configLocation

  • path.public: Directorypublic# Location of

  • ##path.storage: Directory## The location of #storage

  • path.database

    : Directory## The location of #database

    ##path.resources
  • : The location of the directoryresources

    path.bootstrap
  • :The location of directorybootstrap

    Second step
  • , save the current

Illuminate\Foundation/Applicationinstance to$instance class variable, and at the same time bind to the service container for singleton binding, the binding name isapp orContainer::class##The third step, perform registration in sequence

Illuminate\Events\EventServiceProvider,Illuminate\Log\LogServiceProviderandIlluminate\Routing\RoutingServiceProviderThree service providers;The order of registering service providers is as follows:

If the class variable

    $serviceProviders
  • already exists the service provider and does not require forced re-registration, return the service Provider instance$provider;has not registered the current service provider, Then continue to execute the following;

  • If the

  • register
  • method exists, execute the service provider Theregistermethod;will the current service provider

  • $provider
  • The instance is saved to the class variable$serviceProvidersarray, and the class variable is markedThe value of$loadedProviders[get_class($provider)]istrue;

  • 判断类变量$booted是否为true,如果是true,则执行服务提供者的boot方法;(类变量$booted应该是标志是否所有服务提供者均注册,框架是否启动)

第四步,注册核心类别名;
比如
\Illuminate\Foundation\Application::class\Illuminate\Contracts\Container\Container::class起别名为app

单元测试Application的bootstrap启动分析

启动代码很简洁,

Route::get('dev', 'Dev@index'); public function index() { // require 初始化分析上面已经介绍了 $app = require base_path('bootstrap/app.php'); $kernel = $app->make('Illuminate\Contracts\Http\Kernel'); dd($kernel); }
Copy after login

Lets talk about Laravels life cycle

构造函数主要干了一件事,注册一个booted完成后的回调函数,函数执行的内容为“注册Schedule实例到服务提供者,同时加载用户定义的Schedule任务清单”;

bootstrap方法的执行内容如下:

  1. 加载Illuminate/Foundation/Console/Kernel$bootstrappers变量数组中的类,执行它们的bootstrap方法;

  2. protected $bootstrappers = [ // 加载 .env 文件 \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, // 加载 config 目录下的配置文件 \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, // 自定义错误报告,错误处理方法及呈现 \Illuminate\Foundation\Bootstrap\HandleExceptions::class, // 为 config/app.php 中的 aliases 数组注册类别名 \Illuminate\Foundation\Bootstrap\RegisterFacades::class, // 在服务容器中单例绑定一个 request 对象,控制台命令会用到 \Illuminate\Foundation\Bootstrap\SetRequestForConsole::class, // 注册 config\app.php 中的 providers 服务提供者 \Illuminate\Foundation\Bootstrap\RegisterProviders::class, // 项目启动,执行每个 ServiceProvider 的 boot 方法, \Illuminate\Foundation\Bootstrap\BootProviders::class, ];
    Copy after login
  3. 加载延迟的服务提供者;

Http访问Application的bootstrap启动分析

启动入口文件在public\index.php

$app = require_once __DIR__.'/../bootstrap/app.php'; // 实例化 Illuminate/Foundation/Http/Kernel 对象 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); // 中间件处理、业务逻辑处理 $response = $kernel->handle( // 根据 Symfony 的 request 对象封装出 Illuminate\Http\Request $request = Illuminate\Http\Request::capture() ); $response->send(); // 执行所有中间件的 terminate 方法,执行 Application 中的 terminatingCallbacks 回调函数 $kernel->terminate($request, $response);
Copy after login

重要的类变量数组

aliases数组

维护 类与别名 的数组;键名为 类的全限定类名,键值为 数组,每一个元素都是该类的别名;

判断指定类是否有别名:app()->isAlias($name)

获取指定类的别名:app()->getAlias($abstract)

abstractAliases数组

维护 类与别名 的数组;键名为 别名,键值为 类的全限定类名;

instances数组

维护 类与实例的数组;键名为 类的全限定类名,键值为该类的实例;

移除绑定类:app()->forgetInstance($abstract);

移除所有绑定类:app()->forgetInstances();

bindings数组

通过bind方法实现 接口类与实现的绑定;

获取bindings数组中的内容:app()->getBindings()

resolved数组

键名为 类的全限定类名,键值为布尔值类型(true表示已解析过,false表示未解析过);

with 数组

resolved过程中,会有一些参数;with数组就是参数栈,开始解析时将参数入栈,结束解析时参数出栈;

contextual数组

上下文绑定数组;第一维数组键名为 场合类(比如某个Controller类的类名),第二维数组键名为 抽象类(需要实现的接口类),键值为Closure或 某个具体类的类名;

tags数组

维护 标签与类 的数组;键名是 标签名,键值是 对应要绑定的类的名称;

如果调用tagged方法,会将键值数组中的类都make出来,并以数组形式返回;

extenders数组

makeresolve出对象的时候,会执行

foreach ($this->getExtenders($abstract) as $extender) { $object = $extender($object, $this);}
Copy after login

能对解析出来的对象进行修饰;

methodBindings数组

向容器绑定方法与及实现:app()->bindMethod($method, $callback)

判断容器内是否有指定方法的实现:app()->hasMethodBinding($method)
执行方法的实现:app()->callMethodBinding($method, $instance)或者app()->call($method)

buildStack数组

调用build方法时维护的栈,栈中存放的是当前要new的类名;

reboundCallbacks数组

当调用rebound函数时,会触发rebound中为此$abstract设置的回调函数;

注册入口:app()->rebinding($abstract, Closure $callback);

serviceProviders数组

已在系统注册的服务提供者ServiceProvider

数组内存放的是loadedProviders键名对应类的实例;

loadedProviders数组

系统已加载的ServiceProvider的集合;键名为ServiceProvider的全限定类名,键值为布尔值(true表示已加载,false表示未加载);

获取延迟加载对象:app()->getLoadedProviders();

deferredServices数组

有些服务提供者是会延迟加载的;这时候会将这些服务提供者声明的服务登录在deferredServices数组,键名为延迟加载对象名 ,键值为该延迟加载对象所在的ServiceProvider

获取延迟加载对象:app()->getDeferredServices();

bootingCallbacks数组

项目启动前执行的回调函数;(项目启动是在执行\Illuminate\Foundation\Bootstrap\BootProviders::class的时候)

注册入口:app()->booting($callback);

bootedCallbacks数组

项目启动后执行的回调函数;(项目启动是在执行\Illuminate\Foundation\Bootstrap\BootProviders::class的时候)

注册入口:app()->booted($callback);

resolvingCallbacks数组

解析时回调函数集合;键名为 类名, 键值为 回调函数数组,每一个元素都是回调函数;

注册入口:app()->resolving($abstract, $callback);

afterResolvingCallbacks数组

解析后回调函数集合;键名为 类名, 键值为 回调函数数组,每一个元素都是回调函数;

注册入口:app()->afterResolving($abstract, $callback);

globalResolvingCallbacks数组

全局解析时回调函数集合;每一次resolve方法调用时都会执行的回调函数集合;

注册入口:app()->resolving($callback);

globalAfterResolvingCallbacks数组

全局解析后回调函数集合;每一次resolve方法调用后都会执行的回调函数集合;

注册入口:app()->afterResolving($callback);

terminatingCallbacks数组

系统在返回response之后,会执行terminate方法,来做应用结束前的扫尾处理;

这个数组就是执行terminate方法时会执行的回调函数集合;

注册入口:app()->terminating(Closure $callback);

常用方法的解析

bind方法

public function bind($abstract, $concrete = null, $shared = false)
Copy after login

第一个参数是要注册的类名或接口名,第二个参数是返回类的实例的闭包(或类的实例类名),第三个参数是否是单例;

方法内部流程:

  1. unsetinstancesaliases数组中键值为$abstract的元素;

  2. 如果$concrete值为null,将$abstract赋值给$concrete

  3. 如果$concrete不是Closure对象,则封装成闭包;

  4. $concrete$shared通过compact,添加进bindings数组,键名为$abstract

  5. 判断$abstractresolvedinstances数组中是否存在,如果存在,则执行第 6 步;

  6. 触发rebound回调函数;如果reboundCallbacks数组中注册以$abstract为键名的回调函数,则执行这些回调函数;

涉及数组:instancesaliases(unset 操作)、bindings(add 操作)

singleton方法

单例绑定;

public function singleton($abstract, $concrete = null) $this->bind($abstract, $concrete, true);}
Copy after login

涉及数组:instancesaliases(unset 操作)、bindings(add 操作)

bindIf方法

单例绑定;

public function bindIf($abstract, $concrete = null, $shared = false) { if (! $this->bound($abstract)) { $this->bind($abstract, $concrete, $shared); } }
Copy after login

涉及数组:instancesaliases(unset 操作)、bindings(add 操作)

instance方法

绑定实例;

public function instance($abstract, $instance)
Copy after login

方法内部流程:

  1. 如果$abstractaliases数组中存在,则从abstractAliases中所有的值数组中移除该类;

  2. unsetaliases数组中键名为$abstract的元素;

  3. 赋值操作:$this->instances[$abstract] = $instance;

  4. 判断$abstractresolvedinstances数组中是否存在,如果存在,则执行第 5 步;

  5. 触发rebound回调函数;如果reboundCallbacks数组中注册以$abstract为键名的回调函数,则执行这些回调函数;

涉及数组:instances(add 操作)、aliasesabstractAliases(unset 操作)

make方法

public function make($abstract) { return $this->resolve($abstract);}
Copy after login

alias

给类起别名;

public function alias($abstract, $alias) { $this->aliases[$alias] = $abstract; $this->abstractAliases[$abstract][] = $alias; }
Copy after login

涉及数组:aliasesabstractAliases(add 操作)

laravel 的源代码生命周期

第一步 Laravel 应用的所有请求入口都是 public/index.php 文件。打开 index.php 发现代码也就几行。

下面我们来讲一下每一句代码的作用是什么?

// 定义了laravel一个请求的开始时间 define('LARAVEL_START', microtime(true)); // composer自动加载机制 require __DIR__.'/../vendor/autoload.php'; // 这句话你就可以理解laravel,在最开始引入了一个ioc容器。 $app = require_once __DIR__.'/../bootstrap/app.php'; // 打开__DIR__.'/../bootstrap/app.php';你会发现这段代码,绑定了Illuminate\Contracts\Http\Kernel::class, // 这个你可以理解成之前我们所说的$ioc->bind();方法。 // $app->singleton( // Illuminate\Contracts\Http\Kernel::class, // App\Http\Kernel::class // ); // 这个相当于我们创建了Kernel::class的服务提供者 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); // 获取一个 Request ,返回一个 Response。以把该内核想象作一个代表整个应用的大黑盒子,输入 HTTP 请求,返回 HTTP 响应。 $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ); // 就是把我们服务器的结果返回给浏览器。 $response->send(); // 这个就是执行我们比较耗时的请求, $kernel->terminate($request, $response);
Copy after login

走到这里你会发现,是不是在我们学会了 ioc,服务提供者理解起来就比较简单了。那 $middleware,服务提供者都是在哪个文件注册运行的呢?

打开 App\Http\Kernel::class 这个文件,你会发现定义了一堆需要加载的 $middleware。这个 kernel 的主要方法还是在他的父类里面 Illuminate\Foundation\Http\Kernel 中。

打开 Illuminate\Foundation\Http\Kernel,你会发现定义了启动时需要做的事呢?

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, ];
Copy after login

$bootstrappers 就定义了我们的 RegisterFacades.class,RegisterProviders.class 这两个类的意思就是要将我们在 app.config 中的 Providers,Facades 注入到我们的 Ioc 容器中。

【相关推荐:laravel视频教程

The above is the detailed content of Let's talk about Laravel's life cycle. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:csdn.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!