目錄
Laravel的生命週期A
PHP 的運行模式
PHP 的生命週期
Laravel 的请求步骤" >Laravel 的请求步骤
Laravel的生命周期 B
laravel/public/index.php" >laravel/public/index.php
laravel/boostrap/app.php" >laravel/boostrap/app.php
laravel\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php" >laravel\vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php
Laravel 服务容器模块" >Laravel 服务容器模块
简介
框架调用分析
Application初始化
单元测试Application的bootstrap启动分析
Http访问Application的bootstrap启动分析
重要的类变量数组
aliases数组
abstractAliases数组
instances数组
bindings数组
resolved数组
with 数组
contextual数组
tags数组
extenders数组
methodBindings数组
buildStack数组
reboundCallbacks数组
serviceProviders数组
loadedProviders数组
deferredServices数组
bootingCallbacks数组
bootedCallbacks数组
resolvingCallbacks数组
afterResolvingCallbacks数组
globalResolvingCallbacks数组
globalAfterResolvingCallbacks数组
terminatingCallbacks数组
常用方法的解析
bind方法
singleton方法
bindIf方法
instance方法
make方法
alias
laravel 的源代码生命周期
首頁 php框架 Laravel 一起來聊聊Laravel的生命週期

一起來聊聊Laravel的生命週期

Apr 25, 2022 pm 12:04 PM
laravel

這篇文章為大家帶來了關於laravel的相關知識,其中主要介紹了關於Laravel的生命週期相關問題,Laravel 的生命週期從public\index.php開始,從public\ index.php結束,希望對大家有幫助。

一起來聊聊Laravel的生命週期

【相關推薦:laravel影片教學

Laravel的生命週期A

世間萬物皆有生命週期,當我們使用任何工具時都需要理解它的工作原理,那麼用起來就會得心應手,應用開發也是如此。理解了它的原理,那麼使用起來就會游刃有餘。

在了解 Laravel 的生命週期之前,我們先回顧一下PHP 的生命週期。

PHP 的運行模式

PHP兩種運行模式分別是WEB模式、CLI模式。

當我們在終端機敲入php這個指令的時候,使用的是CLI模式。

當使用Nginx或別web伺服器作為宿主處理一個到來的請求時,使用的是WEB模式。

PHP 的生命週期

當我們請求一個php檔案時,PHP 為了完成這次請求,會發生5個階段的生命週期切換:

  • 1 模組初始化(MINIT),即呼叫php.ini 中指明的擴充功能的初始化函數進行初始化工作,如mysql 擴充。

  • 2 請求初始化(RINIT),即初始化為執行本次腳本所需的變數名稱和變數值內容的符號表,如 $_SESSION變數。

  • 3 執行該PHP腳本。

  • 4 請求處理完成(Request Shutdown),依序呼叫各個模組的 RSHUTDOWN 方法,對每個變數呼叫 unset 函數,如 unset $_SESSION 變數。

  • 5 關閉模組(Module Shutdown) , PHP呼叫每個擴充的 MSHUTDOWN 方法,這是各個模組最後一次釋放記憶體的機會。這意味著沒有下一個請求了。

WEB模式和CLI(命令列)模式很相似,差異是:

CLI 模式會在每次腳本執行經歷完整的5個週期,因為你腳本執行完不會有下一個請求;

#WEB模式為了應對並發,可能採用多線程,因此生命週期1和5有可能只執行一次,下次請求到來時重複2-4的生命週期,這樣就節省了系統模組初始化所帶來的開銷。

可以看出PHP生命週期是很對稱的。說了這麼多,就是為了定位Laravel運行在哪裡,沒錯,Laravel僅僅運行再第三個階段:

一起來聊聊Laravel的生命週期

##作用

理解這些,你就可以優化你的Laravel 程式碼,可以更深入的了解Laravel 的singleton(單例)。

至少你知道了,每次要求結束,PHP 的變數都會unset,Laravel 的singleton 只是在某一次請求過程中的singleton;<span style="font-size: 14px;"></span>

#你在Laravel 中的靜態變數也不能在多個請求之間共享,因為每個請求結束都會unset。 <span style="font-size: 14px;"></span>

理解這些概念,是寫高品質程式碼的第一步,也是最關鍵的一步。因此記住,PHP是一種腳本語言,所有的變數只會在這次請求中生效,下次請求時已被重置,而不像Java靜態變數擁有全域作用。 <span style="font-size: 14px;"></span>

Laravel 的生命週期

概述<span style="font-size: 14px;"></span>

#Laravel 的生命週期從public\index.php開始,從public\ index.php結束。 <span style="font-size: 14px;"></span>

一起來聊聊Laravel的生命週期

請求過程<span style="font-size: 14px;"></span>

#下面是public\index.php的全部原始碼,更具體來說可分為四個步驟:<span style="font-size: 14px;"></span>

<?php define(&#39;LARAVEL_START&#39;, microtime(true));

require __DIR__.&#39;/../vendor/autoload.php&#39;;

$app = require_once __DIR__.&#39;/../bootstrap/app.php&#39;;

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

$response->send();

$kernel->terminate($request, $response);
登入後複製

以下是四步驟詳細的解釋是:composer自動載入所需的類別<span style="font-size: 14px;"></span>

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

一起來聊聊Laravel的生命週期

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',    ];
登入後複製

一起來聊聊Laravel的生命週期

Laravel的生命周期 B

一起來聊聊Laravel的生命週期

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);
登入後複製

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;
登入後複製

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();
    }
登入後複製

Laravel 服务容器模块

简介

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

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

框架调用分析

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

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

<span style="font-size: 14px;">Illuminate\Foundation/Application</span>是对<span style="font-size: 14px;">Illuminate\Container\Container</span>的又一层封装;

Application初始化

那么实例化<span style="font-size: 14px;">Illuminate\Foundation/Application</span>时,做了什么呢?

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

  • <span style="font-size: 14px;">path</span>:目錄<span style="font-size: 14px;"></span>#的位置

  • <span style="font-size: 14px;">path.base</span>:專案根目錄的位置

  • <span style="font-size: 14px;">#path.lang</span>:目錄<span style="font-size: 14px;">#resources/lang</span>的位置

  • <span style="font-size: 14px;">path.config</span>:目錄<span style="font-size: 14px;">config</span>的位置

  • <span style="font-size: 14px;">path.public</span>#:目錄##public<span style="font-size: 14px;"></span>的位置<span style="font-size: 14px;"></span>

  • path.storage<span style="font-size: 14px;"></span>:目錄<span style="font-size: 14px;"></span> #storage<span style="font-size: 14px;"></span>的位置<span style="font-size: 14px;"></span>

  • #path.database<span style="font-size: 14px;"></span>##:目錄<span style="font-size: 14px;"></span>database<span style="font-size: 14px;"></span>的位置<span style="font-size: 14px;"></span>

  • path.resources<span style="font-size: 14px;"></span>:目錄<span style="font-size: 14px;"></span>resources<span style="font-size: 14px;"></span>的位置<span style="font-size: 14px;"></span>

  • path.bootstrap<span style="font-size: 14px;"></span>:目錄<span style="font-size: 14px;"></span>bootstrap<span style="font-size: 14px;"></span>#的位置<span style="font-size: 14px;"></span>

第二步,將目前Illuminate\Foundation/Application<span style="font-size: 14px;"></span>實例儲存到<span style="font-size: 14px;"></span>$instance<span style="font-size: 14px;"></span>類別變量,並同時綁定到服務容器作單例綁定,綁定名為<span style="font-size: 14px;"></span>#app<span style="font-size: 14px;"></span>或 <span style="font-size: 14px;"></span>Container::class<span style="font-size: 14px;"></span>;<span style="font-size: 14px;"></span>

#第三步驟,順序分別執行註冊Illuminate\Events\EventServiceProvider<span style="font-size: 14px;"></span>、<span style="font-size: 14px;"></span>Illuminate\Log\LogServiceProvider<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>

<span style="font-size: 14px;"></span>

  • Illuminate\Routing\RoutingServiceProvider<span style="font-size: 14px;"></span>三個服務提供者;<span style="font-size: 14px;"></span>註冊服務提供者的順序如下:<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>

    #如果類別變數
  • $serviceProviders<span style="font-size: 14px;"></span>

    已經存在該服務提供者且不需要強制重新註冊,則傳回服務提供者實例
  • $provider<span style="font-size: 14px;"></span>;<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>未註冊過目前服務提供者,則繼續執行以下;<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>

    如果存在
  • #register<span style="font-size: 14px;"></span>方法,執行服務提供者的<span style="font-size: 14px;"></span>register<span style="font-size: 14px;"></span>方法;<span style="font-size: 14px;"></span><span style="font-size: 14px;"></span>將目前服務提供者<span style="font-size: 14px;"></span>$provider<span style="font-size: 14px;"></span>實例儲存到類別變數<span style="font-size: 14px;"></span>$serviceProviders<span style="font-size: 14px;"></span>

    陣列中,同時標記類別變數### ######$loadedProviders[get_class($provider)]##########的值為#########true#########################;### ###
  • 判断类变量<span style="font-size: 14px;">$booted</span>是否为<span style="font-size: 14px;">true</span>,如果是<span style="font-size: 14px;">true</span>,则执行服务提供者的<span style="font-size: 14px;">boot</span>方法;(类变量<span style="font-size: 14px;">$booted</span>应该是标志是否所有服务提供者均注册,框架是否启动)

第四步,注册核心类别名;
比如
<span style="font-size: 14px;">\Illuminate\Foundation\Application::class</span><span style="font-size: 14px;">\Illuminate\Contracts\Container\Container::class</span>起别名为<span style="font-size: 14px;">app</span>

单元测试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);
}
登入後複製

一起來聊聊Laravel的生命週期

构造函数主要干了一件事,注册一个<span style="font-size: 14px;">booted</span>完成后的回调函数,函数执行的内容为“注册 <span style="font-size: 14px;">Schedule</span>实例到服务提供者,同时加载用户定义的<span style="font-size: 14px;">Schedule</span>任务清单”;

<span style="font-size: 14px;">bootstrap</span>方法的执行内容如下:

  1. 加载<span style="font-size: 14px;">Illuminate/Foundation/Console/Kernel</span><span style="font-size: 14px;">$bootstrappers</span>变量数组中的类,执行它们的<span style="font-size: 14px;">bootstrap</span>方法;

  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,
    ];
    登入後複製
  3. 加载延迟的服务提供者;

Http访问Application的bootstrap启动分析

启动入口文件在<span style="font-size: 14px;">public\index.php</span>

$app = require_once __DIR__.&#39;/../bootstrap/app.php&#39;;

// 实例化 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);
登入後複製

重要的类变量数组

aliases数组

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

判断指定类是否有别名:<span style="font-size: 14px;">app()->isAlias($name)</span>

获取指定类的别名:<span style="font-size: 14px;">app()->getAlias($abstract)</span>

abstractAliases数组

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

instances数组

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

移除绑定类:<span style="font-size: 14px;">app()->forgetInstance($abstract);</span>

移除所有绑定类:<span style="font-size: 14px;">app()->forgetInstances();</span>

bindings数组

通过 <span style="font-size: 14px;">bind</span> 方法实现 接口类与实现的绑定;

获取<span style="font-size: 14px;">bindings</span>数组中的内容:<span style="font-size: 14px;">app()->getBindings()</span>

resolved数组

键名为 类的全限定类名,键值为布尔值类型(<span style="font-size: 14px;">true</span>表示已解析过,<span style="font-size: 14px;">false</span>表示未解析过);

with 数组

<span style="font-size: 14px;">resolved</span>过程中,会有一些参数;<span style="font-size: 14px;">with</span>数组就是参数栈,开始解析时将参数入栈,结束解析时参数出栈;

contextual数组

上下文绑定数组;第一维数组键名为 场合类(比如某个<span style="font-size: 14px;">Controller</span>类的类名),第二维数组键名为 抽象类(需要实现的接口类),键值为 <span style="font-size: 14px;">Closure</span> 或 某个具体类的类名;

tags数组

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

如果调用<span style="font-size: 14px;">tagged</span>方法,会将键值数组中的类都<span style="font-size: 14px;">make</span>出来,并以数组形式返回;

extenders数组

<span style="font-size: 14px;">make</span><span style="font-size: 14px;">resolve</span>出对象的时候,会执行

foreach ($this->getExtenders($abstract) as $extender) {    $object = $extender($object, $this);}
登入後複製

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

methodBindings数组

向容器绑定方法与及实现:<span style="font-size: 14px;">app()->bindMethod($method, $callback)</span>

判断容器内是否有指定方法的实现:<span style="font-size: 14px;">app()->hasMethodBinding($method)</span>
执行方法的实现:<span style="font-size: 14px;">app()->callMethodBinding($method, $instance)</span>或者<span style="font-size: 14px;">app()->call($method)</span>

buildStack数组

调用<span style="font-size: 14px;">build</span>方法时维护的栈,栈中存放的是当前要<span style="font-size: 14px;">new</span>的类名;

reboundCallbacks数组

当调用<span style="font-size: 14px;">rebound</span>函数时,会触发<span style="font-size: 14px;">rebound</span>中为此<span style="font-size: 14px;">$abstract</span>设置的回调函数;

注册入口:<span style="font-size: 14px;">app()->rebinding($abstract, Closure $callback);</span>

serviceProviders数组

已在系统注册的服务提供者<span style="font-size: 14px;">ServiceProvider</span>

数组内存放的是<span style="font-size: 14px;">loadedProviders</span>键名对应类的实例;

loadedProviders数组

系统已加载的<span style="font-size: 14px;">ServiceProvider</span>的集合;键名为<span style="font-size: 14px;">ServiceProvider</span>的全限定类名,键值为布尔值(<span style="font-size: 14px;">true</span>表示已加载,<span style="font-size: 14px;">false</span>表示未加载);

获取延迟加载对象:<span style="font-size: 14px;">app()->getLoadedProviders()</span>;

deferredServices数组

有些服务提供者是会延迟加载的;这时候会将这些服务提供者声明的服务登录在<span style="font-size: 14px;">deferredServices</span>数组,键名为延迟加载对象名 ,键值为该延迟加载对象所在的<span style="font-size: 14px;">ServiceProvider</span>

获取延迟加载对象:<span style="font-size: 14px;">app()->getDeferredServices()</span>;

bootingCallbacks数组

项目启动前执行的回调函数;(项目启动是在执行<span style="font-size: 14px;">\Illuminate\Foundation\Bootstrap\BootProviders::class</span>的时候)

注册入口:<span style="font-size: 14px;">app()->booting($callback);</span>

bootedCallbacks数组

项目启动后执行的回调函数;(项目启动是在执行<span style="font-size: 14px;">\Illuminate\Foundation\Bootstrap\BootProviders::class</span>的时候)

注册入口:<span style="font-size: 14px;">app()->booted($callback);</span>

resolvingCallbacks数组

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

注册入口:<span style="font-size: 14px;">app()->resolving($abstract, $callback);</span>

afterResolvingCallbacks数组

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

注册入口:<span style="font-size: 14px;">app()->afterResolving($abstract, $callback);</span>

globalResolvingCallbacks数组

全局解析时回调函数集合;每一次<span style="font-size: 14px;">resolve</span>方法调用时都会执行的回调函数集合;

注册入口:<span style="font-size: 14px;">app()->resolving($callback);</span>

globalAfterResolvingCallbacks数组

全局解析后回调函数集合;每一次<span style="font-size: 14px;">resolve</span>方法调用后都会执行的回调函数集合;

注册入口:<span style="font-size: 14px;">app()->afterResolving($callback);</span>

terminatingCallbacks数组

系统在返回<span style="font-size: 14px;">response</span>之后,会执行<span style="font-size: 14px;">terminate</span>方法,来做应用结束前的扫尾处理;

这个数组就是执行<span style="font-size: 14px;">terminate</span>方法时会执行的回调函数集合;

注册入口:<span style="font-size: 14px;">app()->terminating(Closure $callback)</span>;

常用方法的解析

bind方法

public function bind($abstract, $concrete = null, $shared = false)
登入後複製

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

方法内部流程:

  1. <span style="font-size: 14px;">unset</span>instancesaliases 数组中键值为 <span style="font-size: 14px;">$abstract</span> 的元素;

  2. 如果 <span style="font-size: 14px;">$concrete</span> 值为 <span style="font-size: 14px;">null</span> ,将 <span style="font-size: 14px;">$abstract</span> 赋值给 <span style="font-size: 14px;">$concrete</span>

  3. 如果 <span style="font-size: 14px;">$concrete</span> 不是 <span style="font-size: 14px;">Closure</span> 对象,则封装成闭包;

  4. <span style="font-size: 14px;">$concrete</span><span style="font-size: 14px;">$shared</span> 通过 <span style="font-size: 14px;">compact</span>,添加进 bindings 数组,键名为 <span style="font-size: 14px;">$abstract</span>

  5. 判断 <span style="font-size: 14px;">$abstract</span>resolvedinstances 数组中是否存在,如果存在,则执行第 6 步;

  6. 触发 <span style="font-size: 14px;">rebound</span>回调函数;如果 <span style="font-size: 14px;">reboundCallbacks</span> 数组中注册以 <span style="font-size: 14px;">$abstract</span> 为键名的回调函数,则执行这些回调函数;

涉及数组:<span style="font-size: 14px;">instances</span><span style="font-size: 14px;">aliases</span>(unset 操作)、<span style="font-size: 14px;">bindings</span>(add 操作)

singleton方法

单例绑定;

public function singleton($abstract, $concrete = null)    $this->bind($abstract, $concrete, true);}
登入後複製

涉及数组:<span style="font-size: 14px;">instances</span><span style="font-size: 14px;">aliases</span>(unset 操作)、<span style="font-size: 14px;">bindings</span>(add 操作)

bindIf方法

单例绑定;

public function bindIf($abstract, $concrete = null, $shared = false) {
    if (! $this->bound($abstract)) {
        $this->bind($abstract, $concrete, $shared);
    }
}
登入後複製

涉及数组:<span style="font-size: 14px;">instances</span><span style="font-size: 14px;">aliases</span>(unset 操作)、<span style="font-size: 14px;">bindings</span>(add 操作)

instance方法

绑定实例;

public function instance($abstract, $instance)
登入後複製

方法内部流程:

  1. 如果<span style="font-size: 14px;">$abstract</span><span style="font-size: 14px;">aliases</span>数组中存在,则从<span style="font-size: 14px;">abstractAliases</span>中所有的值数组中移除该类;

  2. <span style="font-size: 14px;">unset</span><span style="font-size: 14px;">aliases</span> 数组中键名为 <span style="font-size: 14px;">$abstract</span>的元素;

  3. 赋值操作:<span style="font-size: 14px;">$this->instances[$abstract] = $instance;</span>

  4. 判断 <span style="font-size: 14px;">$abstract</span>resolvedinstances 数组中是否存在,如果存在,则执行第 5 步;

  5. 触发 <span style="font-size: 14px;">rebound</span>回调函数;如果 <span style="font-size: 14px;">reboundCallbacks</span> 数组中注册以 <span style="font-size: 14px;">$abstract</span> 为键名的回调函数,则执行这些回调函数;

涉及数组:<span style="font-size: 14px;">instances</span>(add 操作)、<span style="font-size: 14px;">aliases</span><span style="font-size: 14px;">abstractAliases</span>(unset 操作)

make方法

public function make($abstract) {    return $this->resolve($abstract);}
登入後複製

alias

给类起别名;

public function alias($abstract, $alias) {
    $this->aliases[$alias] = $abstract;
    
    $this->abstractAliases[$abstract][] = $alias;
}
登入後複製

涉及数组:<span style="font-size: 14px;">aliases</span><span style="font-size: 14px;">abstractAliases</span>(add 操作)

laravel 的源代码生命周期

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

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

// 定义了laravel一个请求的开始时间
define(&#39;LARAVEL_START&#39;, microtime(true));

// composer自动加载机制
require __DIR__.&#39;/../vendor/autoload.php&#39;;

// 这句话你就可以理解laravel,在最开始引入了一个ioc容器。
$app = require_once __DIR__.&#39;/../bootstrap/app.php&#39;;

// 打开__DIR__.&#39;/../bootstrap/app.php&#39;;你会发现这段代码,绑定了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);
登入後複製

走到这里你会发现,是不是在我们学会了 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,
];
登入後複製

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

【相关推荐:laravel视频教程

以上是一起來聊聊Laravel的生命週期的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Laravel和CodeIgniter的最新版本對比 Laravel和CodeIgniter的最新版本對比 Jun 05, 2024 pm 05:29 PM

Laravel9和CodeIgniter4的最新版本提供了更新的功能和改進。 Laravel9採用MVC架構,提供資料庫遷移、驗證及模板引擎等功能。 CodeIgniter4採用HMVC架構,提供路由、ORM和快取。在性能方面,Laravel9的基於服務提供者設計模式和CodeIgniter4的輕量級框架使其具有出色的性能。在實際應用中,Laravel9適用於需要靈活性和強大功能的複雜項目,而CodeIgniter4適用於快速開發和小型應用程式。

Laravel 和 CodeIgniter 中資料處理能力的比較如何? Laravel 和 CodeIgniter 中資料處理能力的比較如何? Jun 01, 2024 pm 01:34 PM

比較Laravel和CodeIgniter的資料處理能力:ORM:Laravel使用EloquentORM,提供類別物件關係映射,而CodeIgniter使用ActiveRecord,將資料庫模型表示為PHP類別的子類別。查詢建構器:Laravel具有靈活的鍊式查詢API,而CodeIgniter的查詢建構器更簡單,基於陣列。資料驗證:Laravel提供了一個Validator類,支援自訂驗證規則,而CodeIgniter的驗證功能內建較少,需要手動編碼自訂規則。實戰案例:用戶註冊範例展示了Lar

Laravel - Artisan 指令 Laravel - Artisan 指令 Aug 27, 2024 am 10:51 AM

Laravel - Artisan 指令 - Laravel 5.7 提供了處理和測試新指令的新方法。它包括測試 artisan 命令的新功能,下面提到了演示?

Laravel 和 CodeIgniter 對於初學者來說哪一個比較友善? Laravel 和 CodeIgniter 對於初學者來說哪一個比較友善? Jun 05, 2024 pm 07:50 PM

對於初學者來說,CodeIgniter的學習曲線更平緩,功能較少,但涵蓋了基本需求。 Laravel提供了更廣泛的功能集,但學習曲線稍陡。在性能方面,Laravel和CodeIgniter都表現出色。 Laravel有更廣泛的文件和活躍的社群支持,而CodeIgniter更簡單、輕量級,具有強大的安全功能。在建立部落格應用程式的實戰案例中,Laravel的EloquentORM簡化了資料操作,而CodeIgniter需要更多的手動配置。

Laravel和CodeIgniter:哪種框架更適合大型專案? Laravel和CodeIgniter:哪種框架更適合大型專案? Jun 04, 2024 am 09:09 AM

在選擇大型專案框架時,Laravel和CodeIgniter各有優勢。 Laravel針對企業級應用程式而設計,提供模組化設計、相依性注入和強大的功能集。 CodeIgniter是一款輕量級框架,更適合小型到中型項目,強調速度和易用性。對於具有複雜需求和大量用戶的大型項目,Laravel的強大功能和可擴展性更為合適。而對於簡單專案或資源有限的情況下,CodeIgniter的輕量級和快速開發能力則較為理想。

PHP 企業級應用微服務架構設計問答 PHP 企業級應用微服務架構設計問答 May 07, 2024 am 09:36 AM

微服務架構使用PHP框架(如Symfony和Laravel)來實現微服務,並遵循RESTful原則和標準資料格式來設計API。微服務透過訊息佇列、HTTP請求或gRPC進行通信,並使用工具(如Prometheus和ELKStack)進行監控和故障排除。

Laravel和CodeIgniter:哪種框架比較適合小型專案? Laravel和CodeIgniter:哪種框架比較適合小型專案? Jun 04, 2024 pm 05:29 PM

對於小型項目,Laravel適用於大型項目,需要強大的功能和安全性。 CodeIgniter適用於非常小的項目,需要輕量級和易用性。

Laravel 和 CodeIgniter 的模板引擎哪一個比較好? Laravel 和 CodeIgniter 的模板引擎哪一個比較好? Jun 03, 2024 am 11:30 AM

比較了Laravel的Blade和CodeIgniter的Twig模板引擎,根據專案需求和個人偏好進行選擇:Blade基於MVC語法,鼓勵良好程式碼組織和模板繼承。 Twig是第三方函式庫,提供靈活語法、強大過濾器、擴充支援和安全沙箱。

See all articles