# laravel生命週期 必看 https://hackmd.io/@javck/ByJgF8HRP/%2FYM2-G97dS8uTbJ2UTDwlRA 必看 https://medium.com/@howhow926/%E6%B7%BA%E8%AB%87-php-laravel-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F-%E8%88%87-%E4%BD%88%E7%BD%B2-c5ad31fddf12 https://learnku.com/articles/10642/laravel-request-life-cycle ![](https://i.imgur.com/xwcRwbH.png) https://hackmd.io/@javck/ByJgF8HRP/%2FYM2-G97dS8uTbJ2UTDwlRA ![](https://i.imgur.com/dI6mbGs.png) 詳細版 不錯看 https://medium.com/@howhow926/%E6%B7%BA%E8%AB%87-php-laravel-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F-%E8%88%87-%E4%BD%88%E7%BD%B2-c5ad31fddf12 絕對要看 https://zhuanlan.zhihu.com/p/328844226 ## 彩雷 如果你model用 triat 然後的話要注意 要防 因為你是準備app 裡面的servicePovider 然後解析app這個大container 這邊解析就會去跑 ## index ![](https://i.imgur.com/UQR7gVK.png) 細說 Laravel 框架 生命周期各階段 運作流程: 1. 第一階段: 主要將框架核心文件與項目中使用的套件,依照 Composer 機制引入至項目內,Composer 引入重點必須確保 "只可引入一次",index.php 作為 Laravel 框架中唯一入口很適合將 PHP autoload 機制放置在這。 1. 第二階段: 創建 app 容器,並綁定三個核心服務內容至 app 容器內。 ![](https://i.imgur.com/uS20DMK.png) 構造函式,文件路徑 : Illuminate/Foundation/Http/Kernel.php 3. 第三階段: 解析 請求來源後去啟動 Http 核心服務,並初始化 該服務定義的中間件( middleware ),以下以 Http 服務為例,在構造函式中已將中間件處理完畢。 ![](https://i.imgur.com/oHEvVeu.png) 各個中間件組,文件路徑 : app/Http/Kernel.php 4. 第四階段: 將 Request 物件 (透過 Illuminate\Http\Request::capture() 捕獲) 傳送至 handle() 內,再來看向 sendRequestThroughRouter() 函式,該函式將 Request 物件 綁定至 app 容器中,並執行 bootstrap() 函式,啟動各個 Provider 服務,最後運行 Pipeline 並返回 Response。 ![](https://i.imgur.com/FKRYLyI.png) 文件路徑 : Illuminate/Foundation/Http/Kernel.php ![](https://i.imgur.com/fyJvqc4.png) 文件路徑 : Illuminate/Foundation/Http/Kernel.php ![](https://i.imgur.com/vO3ocjq.png) 文件路徑 : Illuminate/Foundation/Http/Kernel.php 5. 第五階段: 發送 Response 6. 第六階段: 確認該請求經過的中件間( middleware )中是否含有 terminate() 函式,如有的話則執行,最後中止容器,terminate() 函式使用方式下圖以 hestia 項目中 response 前 saving log middleware 為例。 ![](https://i.imgur.com/oFyDJ03.png) 文件路徑 : app/Http/Middleware/BeforeResponseSaveLog.php ![](https://i.imgur.com/yWmMMpx.png) 由以上各階段流程可看出 Laravel 再取得 Response 後返回 view 前,還是會再一次經過中間件組,這時可以透過這些中間件對 Response 做一些額外操作。 ## PSR PSR-4 将支持更简单的文件夹结构,但是将使我们仅通过查看完全限定的名称就无法知道类的确切路径。 PSR-0 在硬盘驱动器上比较混乱,但是支持念旧的开发人员(类名下划线用户),并帮助我们通过以下方式辨别类的位置:看它的名字。 ## laravel框架下Composer的自动加载源码分析——启动 https://www.cntofu.com/book/107/PHP%20Composer%E2%80%94%E2%80%94%20%E5%88%9D%E5%A7%8B%E5%8C%96%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90.md laravel框架的初始化是需要composer自动加载协助的,所以laravel的入口文件**index.php**第一句就是利用composer来实现自动加载功能。 ``` <?php require __DIR__.'/../bootstrap/autoload.php'; ``` 咱们接着去看 bootstrap 目录下的 **autoload.php** : ``` <?php define('LARAVEL_START', microtime(true)); require __DIR__ . '/../vendor/autoload.php'; ``` 再去 **vendor** 目录下的 **autoload.php** : ``` <?php require_once __DIR__ . '/composer' . '/autoload_real.php'; return ComposerAutoloaderInit832ea71bfb9a4128da8660baedaac82e::getLoader(); ``` 为什么框架要在 `bootstrap/autoload.php` 转一下?个人理解,laravel 这样设计有利于支持或扩展任意有自动加载的第三方库。 好了,我们终于要看到了Composer真正要显威的地方了。**autoload_real.php**里面就是一个自动加载功能的引导类,这个类不负责具体功能逻辑,只做了两件事:初始化自动加载类、注册自动加载类。 到autoload_real这个文件里面去看,发现这个引导类的名字叫ComposerAutoloaderInit832ea71bfb9a4128da8660baedaac82e,为什么要叫这么古怪的名字呢?因为这是**防止用户自定义类名跟这个类重复冲突了**,所以在类名上加了一个hash值。其实还有一个做法我们更加熟悉,那就是不直接定义类名,而是定义一个命名空间。这里为什么不定义一个命名空间呢?个人理解:命名空间一般都是为了复用,而这个类只需要运行一次即可,以后也不会用得到,用hash值更加合适。 ## laravel框架下Composer的自动加载源码分析——autoload_real引导类 在 vendor 目录下的 autoload.php 文件中我们可以看出,程序主要调用了引导类的静态方法 getLoader() ,我们接着看看这个函数。 ``` <?php public static function getLoader() { /***************************经典单例模式********************/ if (null !== self::$loader) { return self::$loader; } /***********************获得自动加载核心类对象********************/ spl_autoload_register( array('ComposerAutoloaderInit832ea71bfb9a4128da8660baedaac82e', 'loadClassLoader'), true, true ); self::$loader = $loader = new \Composer\Autoload\ClassLoader(); spl_autoload_unregister( array('ComposerAutoloaderInit832ea71bfb9a4128da8660baedaac82e', 'loadClassLoader') ); /***********************初始化自动加载核心类对象********************/ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION'); if ($useStaticLoader) { require_once __DIR__ . '/autoload_static.php'; call_user_func( \Composer\Autoload\ComposerStaticInit832ea71bfb9a4128da8660baedaac82e::getInitializer($loader) ); } else { $map = require __DIR__ . '/autoload_namespaces.php'; foreach ($map as $namespace => $path) { $loader->set($namespace, $path); } $map = require __DIR__ . '/autoload_psr4.php'; foreach ($map as $namespace => $path) { $loader->setPsr4($namespace, $path); } $classMap = require __DIR__ . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } } /***********************注册自动加载核心类对象********************/ $loader->register(true); /***********************自动加载全局函数********************/ if ($useStaticLoader) { $includeFiles = Composer\Autoload\ComposerStaticInit832ea71bfb9a4128da8660baedaac82e::$files; } else { $includeFiles = require __DIR__ . '/autoload_files.php'; } foreach ($includeFiles as $fileIdentifier => $file) { composerRequire832ea71bfb9a4128da8660baedaac82e($fileIdentifier, $file); } return $loader; } ``` 詳細去看文章 ## index.php https://hackmd.io/Kyq9u9WcTJqheOZKmAPEvw ``` require __DIR__.'/../bootstrap/autoload.php'; $app = require_once __DIR__.'/../bootstrap/app.php'; $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle( $request = Illuminate\Http\Request::capture() ```  第一句就是我们前面博客说的composer的自动加载,接下来第二句获取laravel核心的Ioc容器,第三句“制造”出Http请求的内核,第四句是我们这里的关键,这句牵扯很大,laravel里面所有功能服务的注册加载,乃至Http请求的构造与传递都是这一句的功劳。 ``` $request = Illuminate\Http\Request::capture() ``` 这句是laravel通过全局$_SERVER数组构造一个Http请求的语句,接下来会调用Http的内核函数handle: 簡單來說是建立組件 註冊Facades Providers之類的組件,註冊aliases别名之類的很多 ## bootstrap/app.php 第一步,当用户在浏览器访问 URL 时会发起一个 HTTP 请求,最终这个请求被发送到我们的 Web 服务器。Web 服务器(Apache 或 Nginx) 通过匹配的服务配置,再将请求发送到 Laravel 中的 入口文件 public/index.php,该文件完成项目依赖服务的加载功能。首先它将 composer 生成的自动加载器引入项目(译注:require DIR.'/../vendor/autoload.php';)。 然后接收由 bootstrap/app.php 文件创建的应用实例。创建实例的过程即是项目初始化的过程。 裡面接著kernel 這邊會去拉index的東西好像是dir不確定,反正會跟index交互,然後用ioc之後去跑kernel ## kernel Kernel 类的内部有定义诸多的 引导程序(Bootstrappers),这些引导程序会完成错误句柄(handle)配置、日志配置、运行环境识别和所有需要在请求被执行前完成的配置工作。 不仅如此,Kernel 类还定义了许多需要在请求被处理前需要被执行的中间件 ## Service Provider 接著上面 接下来,内核会在引导项目启动时加载服务提供者。应用实例所依赖的服务提供者可以在 config/app.php 配置文件中的 providers 节点找到。 一个服务提供者的 register() 方法被调用时,这个服务提供者即被注册到应用实例。完成所有服务提供者注册到应用实例后,应用实例执行启动方法(boot method)引导项目启动 ## 分发请求 随着应用实例完成引导、注册服务器提供者和启动等处理,接下来请求便会被路由器(Router)转发。路由器将请求转发至注册的路由和对应的控制器(译注:在 routes/web.php 或 routes/api.php 文件中定义的路由),并且执行当前路由相关的中间件。 ## http流程 1 用户在浏览器输入 http://xyz.com 并点击回车按钮。 2 当用户点击回车按钮,浏览器将页面的请求通过网络发送到 Web 服务器。 3 Web 服务器接收请求并解析请求信息。在 Web 服务器的配置文件中有配置当前项目根目录路径。由于当前访问的 URL 地址不包含子路径,Web 服务器会查找配置文件的 index.php 文件。 4 Web 服务器将请求发送到项目的 public/index.php 文件。 5 PHP 解释器接收到请求后,解释执行 index.php 文件中的 PHP 代码。此时,由 Componser 包管理器生成的自动加载文件被加载。 6 之后,Laravel 应用实例被实例化,同时,引导安装 laravel 组件(bootrap 做ioc容器 接下來就能用容器去跑kernel)。 7 HTTP 或 Console 内核接收到 HTTP 请求,加载 Laravel 服务提供者,同时,将请求分发给路由器执行。 8 路由器将渲染视图文件,并生成响应数据给 Web 服务器。 9 Web 服务器接收到 PHP 的输出结果,并将结果返回给用户浏览器。 10 用户浏览器接收到服务器响应,渲染页面并展现给用户。 ###### tags: `Laravel`