> PHP 프레임워크 > Laravel > Laravel의 라이프사이클에 대해 이야기해 봅시다.

Laravel의 라이프사이클에 대해 이야기해 봅시다.

WBOY
풀어 주다: 2022-04-25 12:04:13
앞으로
3465명이 탐색했습니다.

이 글은 laravel에 대한 관련 지식을 제공하며, Laravel의 라이프 사이클과 관련된 문제를 주로 소개합니다. Laravel의 라이프 사이클은 publicindex.php에서 시작하여 publicindex.php로 끝나는 모든 분들께 도움이 되기를 바랍니다. .

Laravel의 라이프사이클에 대해 이야기해 봅시다.

【관련 추천: laravel 동영상 튜토리얼

Laravel의 수명주기 A

세상의 모든 것에는 수명주기가 있으므로 도구의 작동 원리를 이해해야 합니다. 그것을 사용하면 편리할 것이며 애플리케이션 개발에도 마찬가지입니다. 원리를 이해하고 나면 쉽게 사용할 수 있을 것입니다.

라라벨의 생명주기를 이해하기에 앞서 먼저 PHP의 생명주기를 살펴보겠습니다.

PHP의 작동 모드

PHP의 작동 모드는 WEB 모드와 CLI 모드 두 가지가 있습니다.

터미널에 php 명령어를 입력하면 CLI 모드를 사용하고 있는 것입니다.

Nginx 또는 다른 웹 서버를 호스트로 사용하여 들어오는 요청을 처리하는 경우 WEB 모드가 사용됩니다.

PHP 라이프 사이클

PHP 파일을 요청하면 PHP는 요청을 완료하기 위해 5단계의 라이프 사이클 전환을 거칩니다.

  • 1 모듈 초기화(MINIT), 즉 php.ini에 지정된 확장의 초기화 함수는 mysql 확장과 같은 초기화 작업을 수행합니다.

  • 2 $_SESSION 변수와 같이 이 스크립트를 실행하는 데 필요한 변수 이름 및 변수 값 내용의 기호 테이블을 초기화하는 요청 초기화(RINIT)입니다.

  • 3 PHP 스크립트를 실행합니다.

  • 4 요청 처리가 완료된 후(Request Shutdown) 각 모듈의 RSHUTDOWN 메소드를 순차적으로 호출하고, unset $_SESSION 변수 등 각 변수에 대해 unset 함수를 호출합니다.

  • 5 모듈 종료(모듈 종료) PHP는 각 확장의 MSHUTDOWN 메서드를 호출합니다. 이는 각 모듈이 메모리를 해제할 수 있는 마지막 기회입니다. 이는 다음 요청이 없음을 의미합니다.

WEB 모드는 CLI(명령줄) 모드와 매우 유사하지만 차이점은 다음과 같습니다.

CLI 모드는 다운로드가 없기 때문에 스크립트가 실행될 때마다 완전한 5주기를 거칩니다. 요청이 실행된 후

WEB 모드는 동시성에 대처하기 위해 멀티스레딩을 사용할 수 있으므로 라이프 사이클 1과 5는 한 번만 실행될 수 있으며 라이프 사이클 2-4는 다음에 요청이 올 때 반복되므로 시스템 모듈 초기화로 인한 오버헤드가 절약됩니다.

PHP 수명주기가 매우 대칭임을 알 수 있습니다. Laravel이 실행되는 위치를 찾는 것뿐입니다. 예, Laravel은 세 번째 단계에서만 실행됩니다.

Laravel의 라이프사이클에 대해 이야기해 봅시다.

Function

이를 이해하면 Laravel 코드를 최적화하고 더 깊이 들어갈 수 있습니다. (단일 사례).

적어도 모든 요청이 끝나면 PHP 변수는 설정 해제됩니다. Laravel의 싱글톤은 특정 요청 중에만 싱글톤입니다.

Laravel의 정적 변수는 여러 요청 간에 공유될 수 없습니다. 그 외는 요청이 끝날 때마다 설정이 해제되기 때문입니다.

이러한 개념을 이해하는 것은 고품질 코드를 작성하기 위한 첫 번째이자 가장 중요한 단계입니다. 따라서 PHP는 스크립팅 언어이며 모든 변수는 전역적으로 영향을 미치는 Java 정적 변수와는 달리 이 요청에서만 적용되며 다음 요청에서 재설정됩니다.

Laravel의 라이프 사이클

개요

Laravel의 라이프 사이클은 publicindex.php에서 시작하여 publicindex.php에서 끝납니다.

Laravel의 라이프사이클에 대해 이야기해 봅시다.

요청 프로세스

다음은 publicindex.php의 전체 소스 코드이며, 보다 구체적으로 4단계로 나눌 수 있습니다.

<?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);
로그인 후 복사

다음은 4단계에 대한 자세한 설명입니다. : Composer 자동 로딩에는 클래스가 필요합니다

  • 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>时,做了什么呢?

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

  • <code><span style="font-size: 14px;">path</span>:目录<span style="font-size: 14px;">app</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>:目录<span style="font-size: 14px;">public</span>的位置

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

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

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

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

第二步,将当前<span style="font-size: 14px;">IlluminateFoundation/Application</span>实例保存到<span style="font-size: 14px;">$instance</span>类变量,并同时绑定到服务容器作单例绑定,绑定名为<span style="font-size: 14px;">app</span><span style="font-size: 14px;">Container::class</span>

第三步,顺序分别执行注册<span style="font-size: 14px;">IlluminateEventsEventServiceProvider</span><span style="font-size: 14px;">IlluminateLogLogServiceProvider</span><span style="font-size: 14px;">IlluminateRoutingRoutingServiceProvider</span>三个服务提供者;

注册服务提供者的顺序如下:

  • 如果类变量<span style="font-size: 14px;">$serviceProviders</span>已经存在该服务提供者并且不需要强制重新注册,则返回服务提供者实例<span style="font-size: 14px;">$provider</span>

  • 未注册过当前服务提供者,则继续执行以下;

  • 如果存在<span style="font-size: 14px;">register</span>方法,执行服务提供者的<span style="font-size: 14px;">register</span>方法;

  • 将当前服务提供者<span style="font-size: 14px;">$provider</span>实例保存到类变量<span style="font-size: 14px;">$serviceProviders</span>数组中,同时标记类变量<span style="font-size: 14px;">$loadedProviders[get_class($provider)]</span>的值为<span style="font-size: 14px;">true</span>path: 디렉터리의 위치

    🎜app🎜🎜🎜🎜
  • 🎜🎜🎜path.base🎜 code> 🎜: 프로젝트 루트 디렉터리의 위치 🎜🎜🎜🎜<code>🎜path.lang🎜🎜: 디렉터리의 위치 🎜🎜resources/lang🎜🎜🎜🎜 li>🎜🎜🎜path.config🎜🎜: 디렉터리 위치 🎜🎜config🎜🎜🎜🎜🎜🎜🎜path.public🎜🎜: 디렉터리의 위치 🎜🎜public🎜🎜 의 위치 🎜🎜🎜🎜🎜🎜 path.database🎜🎜: 디렉터리 🎜🎜database🎜 🎜🎜🎜 🎜🎜🎜path.resources🎜🎜 위치 🎜🎜resources🎜🎜🎜🎜🎜🎜🎜path.bootstrap🎜🎜 디렉토리의 위치: 🎜🎜bootstrap🎜🎜🎜🎜
🎜🎜두 번째 단계, 현재 🎜🎜IlluminateFoundation/ 변경 Application🎜🎜 인스턴스가 🎜에 저장됩니다. 🎜$instance🎜🎜 클래스 변수이며 싱글톤 바인딩을 위해 서비스 컨테이너에도 바인딩됩니다. 바인딩 이름은 🎜🎜app🎜 🎜 또는 🎜🎜Container입니다. ::class🎜🎜;🎜🎜🎜🎜세 번째 단계, 등록 실행 🎜🎜IlluminateEventsEventServiceProvider🎜 code>🎜, 🎜<code>🎜IlluminateLogLogServiceProvider🎜 code>🎜 및 🎜<code>🎜IlluminateRoutingRoutingServiceProvider🎜🎜3개의 서비스 제공자; 🎜🎜🎜🎜서비스 제공자 등록 순서는 다음과 같습니다. 🎜🎜🎜 🎜🎜🎜클래스 변수가 🎜🎜$ serviceProviders🎜🎜가 이미 존재하며 강제 재등록이 필요하지 않습니다. 서비스 공급자 인스턴스 🎜🎜$provider🎜를 반환하세요. 🎜;🎜🎜🎜🎜🎜현재 서비스가 공급자가 등록되지 않은 경우 다음을 계속 실행합니다. 🎜🎜🎜🎜🎜 🎜🎜register🎜🎜 메서드가 있는 경우 서비스 공급자의 🎜🎜register🎜 🎜 메소드; 🎜🎜🎜🎜🎜 현재 서비스 제공자 🎜🎜$provider🎜🎜 인스턴스를 클래스 변수 🎜🎜$serviceProviders🎜에 저장합니다. >🎜배열, 클래스 변수 🎜🎜$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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:csdn.net
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿