Laravel框架执行流程

俗话说知己知彼百战不怠,使用Laravel也有有一段时间了,中间也踩了很多坑,碰了很多壁,归根结底还是对Laravel的底层不太了解,以前使用Thinkphp养成的MVC的习惯,刚接触Laravel一时还没转变过来,所以最近抱着学习的态度,研究了下Laravel框架的执行流程。
Laravel虽然使用上感觉跟Thinkphp差不多,但是底层的实现方式还有框架的架构,跟Thinkphp差别还是蛮大,不过Tp5貌似吸收了很多Laravel中的特性。
废话到此为止,下面上干货

1. 入口文件index.php

1. 引入bootstrap/autoload.php,自动加载依赖库

2. 引入bootstrap/app.php’

  1. 创建容器$app
  1. // 参数为应用程序根目录
  2. $app = new Illuminate\Foundation\Application(
  3. realpath(__DIR__.'/../')
  4. );

 

  • 1
  • 1
  • 2
  • 3
  • 4
  1. 该类是框架核心类,负责启动框架,以及调动其他类提供的功能。
  2. 该类继承了Illuminate\Container\Container类,可见该类也是个容器。是整个框架最大的容器;
  3. 该类的构造器代码如下:
  1. public function __construct($basePath = null)
  2. {
  3. if ($basePath) {
  4. // 设置应用程序根目录
  5. $this->setBasePath($basePath);
  6. }
  7. // 注册基础绑定服务
  8. // 1. 设置当前类为容器实例
  9. // 2. 设置实例别名为app
  10. $this->registerBaseBindings();
  11. // 注册基础服务提供商
  12. // 1. 注册事件服务提供商
  13. // 2. 注册日志服务提供商
  14. // 3. 注册路由服务提供商
  15. $this->registerBaseServiceProviders();
  16. // 注册核心容器别名
  17. // 为一些核心类设置别名,
  18. // 存储在父类的$aliases和abstractAliases属性数组中。
  19. // $aliases 为 别名 => 类名 键值对
  20. // $abstractAliases 为 类名 => 别名 键值对
  21. $this->registerCoreContainerAliases();
  22. }

 

  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  1. 设置接口类的实现类,并使用单例模式实例化实现类。
  1. // 设置HTTP内核实现类
  2. // 配置各种中间件
  3. $app->singleton(
  4. Illuminate\Contracts\Http\Kernel::class,
  5. App\Http\Kernel::class
  6. );
  7. // 设置Console内核实现类
  8. $app->singleton(
  9. Illuminate\Contracts\Console\Kernel::class,
  10. App\Console\Kernel::class
  11. );
  12. // 设置异常处理实现类
  13. $app->singleton(
  14. Illuminate\Contracts\Debug\ExceptionHandler::class,
  15. App\Exceptions\Handler::class
  16. );

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  1. 获得Http内核Kernel的示例
  1. $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

 

  • 1
  • 2

 

  • 1
  • 2
  • 1
  • 2
  1. http内核黑箱操作,接收response。这一步完整个程序的所有操作,形成一个完成的http请求,至于该请求的具体处理,则有kernel内部调度。这里是重点所在。
  2. Http响应,发送Http响应头以及响应内容,代码如下:
  1. $response->send();
  2. /**
  3. * Sends HTTP headers and content.
  4. *
  5. * Symfony\Component\HttpFoundation\Response -> send函数
  6. * @return $this
  7. */
  8. public function send()
  9. {
  10. $this->sendHeaders();
  11. $this->sendContent();
  12. if (function_exists('fastcgi_finish_request')) {
  13. fastcgi_finish_request();
  14. } elseif ('cli' !== PHP_SAPI) {
  15. static::closeOutputBuffers(0, true);
  16. }
  17. return $this;
  18. }

 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  1. 结束所有中间件以及可终止程序
  1. $kernel->terminate($request, $response);
  2. /**
  3. * Call the terminate method on any terminable middleware.
  4. *
  5. * Illuminate\Foundation\Http\Kernel -> terminate函数
  6. * @param \Illuminate\Http\Request $request
  7. * @param \Illuminate\Http\Response $response
  8. * @return void
  9. */
  10. public function terminate($request, $response) {
  11. $this->terminateMiddleware($request, $response);
  12. $this->app->terminate();
  13. }

 

  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

执行流程

  1. 加载框架类库,创建容器,接收request请求。
  2. 以管道的设计模式 执行部分中间件
  3. 路由解析调度
  4. 实例化当前控制器
  5. 执行web中间件
  6. 执行控制器中间件
  7. 执行控制器操作
  8. 返回response
  9. 接收框架

总结

  1. 以前很公共的东西都习惯放在控制器基类的构造函数中,但是在lavarvel5.3以后却不能这么做了,因为由上述执行流程可以看出,web中间件在控制器实例化之后才执行,所以在控制器构造函数执行是session还没有初始化,即在控制器构造函数中获得不了session数据。所以也就获得不了当前用户。所以导致很多操作都做不了了。但是laravel提供了可插拔形式的中间件很好的解决了这个问题。自定义中间件在web中间件之后,Action之前执行。所以很多之前放在构造函数里的操作都可以放在中间件里解决。
  2. laravel框架中使用了大量的static:: (后期静态绑定),单独看代码很难知道调用的函数时那个类的。只有在用运行的时候,才会动态计算出,调用的是那个类的函数。如下面代码:
  1. /*
  2. *
  3. * @see Illuminate\Support\Facades
  4. *
  5. */
  6. public static function __callStatic($method, $args) {
  7. $instance = static::getFacadeRoot();
  8. if (!$instance) {
  9. throw new RuntimeException('A facade root has not been set.');
  10. }
  11. return $instance->$method(...$args);
  12. }

 

  • 1
  • 2
  • 3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这段代码来自 Illuminate\Support\Facades这个类。该类是一个抽象类。我们用的非常多的一个类Auth就是集成该类。
我们都知道Auth中有很多静态函数,如:Auth::check(),Auth::user(),Auth::guest()等等,但是当我们打开Auth类的时候,发现里面并没有这些方法,而他的父类facades中也没有这些方法。只有这个__callStatic函数。从名称不难看出,这是一个静态类的魔术方法。调用所有不存在的静态方法都会调用改函数。
从该函数的实现不难看出,该函数很像是一个工厂函数,获得当前调用函数的实例化对象,然后再调用该函数。 该函数就想是单入口的web程序的入口文件,

可参考另一文章 https://blog.csdn.net/baidu1966/article/details/101459937?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

Laravel框架执行流程
标签: