Laravel框架生命周期与原理分析


Posted in PHP onJune 12, 2018

本文实例讲述了Laravel框架生命周期与原理。分享给大家供大家参考,具体如下:

引言:

如果你对一件工具的使用原理了如指掌,那么你在用这件工具的时候会充满信心!

正文:

一旦用户(浏览器)发送了一个HTTP请求,我们的apache或者nginx一般都转到index.php,因此,之后的一系列步骤都是从index.php开始的,我们先来看一看这个文件代码。

<?php
require __DIR__.'/../bootstrap/autoload.php';
$app = require_once __DIR__.'/../bootstrap/app.php';
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
  $request = Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);

作者在注释里谈了kernel的作用,kernel的作用,kernel处理来访的请求,并且发送相应返回给用户浏览器。

这里又涉及到了一个app对象,所以附上app对象,所以附上app对象的源码,这份源码是\bootstrap\app.php

<?php
/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/
$app = new Illuminate\Foundation\Application(
  realpath(__DIR__.'/../')
);
/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/
$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 The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/
return $app;

请看app变量是Illuminate\Foundation\Application类的对象,所以调用了这个类的构造函数,具体做了什么事,我们看源码。

public function __construct($basePath = null)
{
  if ($basePath) {
    $this->setBasePath($basePath);
  }
  $this->registerBaseBindings();
  $this->registerBaseServiceProviders();
  $this->registerCoreContainerAliases();
}

构造器做了3件事,前两件事很好理解,创建Container,注册了ServiceProvider,看代码

/**
 * Register the basic bindings into the container.
 *
 * @return void
 */
protected function registerBaseBindings()
{
  static::setInstance($this);
  $this->instance('app', $this);
  $this->instance(Container::class, $this);
}
/**
 * Register all of the base service providers.
 *
 * @return void
 */
protected function registerBaseServiceProviders()
{
  $this->register(new EventServiceProvider($this));
  $this->register(new LogServiceProvider($this));
  $this->register(new RoutingServiceProvider($this));
}

最后一件事,是做了个很大的数组,定义了大量的别名,侧面体现程序员是聪明的懒人。

/**
 * Register the core class aliases in the container.
 *
 * @return void
 */
public function registerCoreContainerAliases()
{
  $aliases = [
    'app'         => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class],
    'auth'         => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
    'auth.driver'     => [\Illuminate\Contracts\Auth\Guard::class],
    'blade.compiler'    => [\Illuminate\View\Compilers\BladeCompiler::class],
    'cache'        => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
    'cache.store'     => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
    'config'        => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
    'cookie'        => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
    'encrypter'      => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
    'db'          => [\Illuminate\Database\DatabaseManager::class],
    'db.connection'    => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
    'events'        => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
    'files'        => [\Illuminate\Filesystem\Filesystem::class],
    'filesystem'      => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
    'filesystem.disk'   => [\Illuminate\Contracts\Filesystem\Filesystem::class],
    'filesystem.cloud'   => [\Illuminate\Contracts\Filesystem\Cloud::class],
    'hash'         => [\Illuminate\Contracts\Hashing\Hasher::class],
    'translator'      => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
    'log'         => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::class, \Psr\Log\LoggerInterface::class],
    'mailer'        => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
    'auth.password'    => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
    'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
    'queue'        => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
    'queue.connection'   => [\Illuminate\Contracts\Queue\Queue::class],
    'queue.failer'     => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
    'redirect'       => [\Illuminate\Routing\Redirector::class],
    'redis'        => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
    'request'       => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
    'router'        => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
    'session'       => [\Illuminate\Session\SessionManager::class],
    'session.store'    => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
    'url'         => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
    'validator'      => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
    'view'         => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
  ];
  foreach ($aliases as $key => $aliases) {
    foreach ($aliases as $alias) {
      $this->alias($key, $alias);
    }
  }
}

这里出现了一个instance函数,其实这并不是Application类的函数,而是Application类的父类Container类的函数

/**
 * Register an existing instance as shared in the container.
 *
 * @param string $abstract
 * @param mixed  $instance
 * @return void
 */
public function instance($abstract, $instance)
{
  $this->removeAbstractAlias($abstract);
  unset($this->aliases[$abstract]);
  // We'll check to determine if this type has been bound before, and if it has
  // we will fire the rebound callbacks registered with the container and it
  // can be updated with consuming classes that have gotten resolved here.
  $this->instances[$abstract] = $instance;
  if ($this->bound($abstract)) {
    $this->rebound($abstract);
  }
}

Application是Container的子类,所以$app不仅是Application类的对象,还是Container的对象,所以,新出现的singleton函数我们就可以到Container类的源代码文件里查。bind函数和singleton的区别见这篇博文。

singleton这个函数,前一个参数是实际类名,后一个参数是类的“别名”。

$app对象声明了3个单例模型对象,分别是HttpKernelConsoleKernelExceptionHandler。请注意,这里并没有创建对象,只是声明,也只是起了一个“别名”

大家有没有发现,index.php中也有一个$kernel变量,但是只保存了make出来的HttpKernel变量,因此本文不再讨论,ConsoleKernel,ExceptionHandler。。。

继续在文件夹下找到App\Http\Kernel.php,既然我们把实际的HttpKernel做的事情都写在这个php文件里,就从这份代码里看看究竟做了哪些事?

<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
  /**
   * The application's global HTTP middleware stack.
   *
   * These middleware are run during every request to your application.
   *
   * @var array
   */
  protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    //\App\Http\Middleware\MyMiddleware::class,
  ];
  /**
   * The application's route middleware groups.
   *
   * @var array
   */
  protected $middlewareGroups = [
    'web' => [
      \App\Http\Middleware\EncryptCookies::class,
      \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
      \Illuminate\Session\Middleware\StartSession::class,
      \Illuminate\View\Middleware\ShareErrorsFromSession::class,
      \App\Http\Middleware\VerifyCsrfToken::class,
    ],
    'api' => [
      'throttle:60,1',
    ],
  ];
  /**
   * The application's route middleware.
   *
   * These middleware may be assigned to groups or used individually.
   *
   * @var array
   */
  protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
  'mymiddleware'=>\App\Http\Middleware\MyMiddleware::class,
  ];
}

一目了然,HttpKernel里定义了中间件数组。

该做的做完了,就开始了请求到响应的过程,见index.php

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

最后在中止,释放所有资源。

/**
* Call the terminate method on any terminable middleware.
*
* @param \Illuminate\Http\Request $request
* @param \Illuminate\Http\Response $response
* @return void
*/
public function terminate($request, $response)
{
    $this->terminateMiddleware($request, $response);
    $this->app->terminate();
}

总结一下,简单归纳整个过程就是:

1.index.php加载\bootstrap\app.php,在Application类的构造函数中创建Container,注册了ServiceProvider,定义了别名数组,然后用app变量保存构造函数构造出来的对象。

2.使用app这个对象,创建1个单例模式的对象HttpKernel,在创建HttpKernel时调用了构造函数,完成了中间件的声明。

3.以上这些工作都是在请求来访之前完成的,接下来开始等待请求,然后就是:接受到请求-->处理请求-->发送响应-->中止app变量

希望本文所述对大家基于Laravel框架的PHP程序设计有所帮助。

PHP 相关文章推荐
PHP中常用数组处理方法实例分析
Aug 30 PHP
Drupal 添加模块出现莫名其妙的错误的解决方法(往往出现在模块较多时)
Apr 18 PHP
基于php设计模式中工厂模式详细介绍
May 15 PHP
PHP实现多进程并行操作的详解(可做守护进程)
Jun 18 PHP
linux实现php定时执行cron任务详解
Dec 24 PHP
php中\r \r\n \t的区别示例介绍
Feb 08 PHP
CI框架在CLI下执行占用内存过大问题的解决方法
Jun 17 PHP
php中mail函数发送邮件失败的解决方法
Dec 24 PHP
php随机生成数字字母组合的方法
Mar 18 PHP
Yii 2.0在Grid中格式化时间方法示例
Jun 06 PHP
ThinkPHP防止重复提交表单的方法实例分析
May 10 PHP
PHP中创建和编辑Excel表格的方法
Sep 13 PHP
Laravel框架分页实现方法分析
Jun 12 #PHP
php 可变函数使用小结
Jun 12 #PHP
yii2中关于加密解密的那些事儿
Jun 12 #PHP
php中curl和soap方式请求服务超时问题的解决
Jun 11 #PHP
Laravel框架模板继承操作示例
Jun 11 #PHP
Laravel框架模板加载,分配变量及简单路由功能示例
Jun 11 #PHP
Laravel框架在本地虚拟机快速安装的方法详解
Jun 11 #PHP
You might like
php单态设计模式(单例模式)实例
2014/11/18 PHP
php伪静态验证码不显示的解决方案
2019/09/26 PHP
jQuery 中关于CSS操作部分使用说明
2007/06/10 Javascript
一些Javascript的IE和Firefox(火狐)兼容性的问题总结及常用例子
2009/05/21 Javascript
jQuery DOM操作小结与实例
2010/01/07 Javascript
js 3秒后跳转页面的实现代码
2014/03/10 Javascript
js/jquery判断浏览器的方法小结
2014/09/02 Javascript
javascript实现日期格式转换
2014/12/16 Javascript
JavaScript中的函数(二)
2015/12/23 Javascript
很棒的js Tab选项卡切换效果
2016/08/30 Javascript
Bootstrap table简单使用总结
2017/02/15 Javascript
整理关于Bootstrap表单的慕课笔记
2017/03/29 Javascript
jQuery实现左右滑动的toggle方法
2018/03/03 jQuery
vue2.0 自定义组件的方法(vue组件的封装)
2018/06/05 Javascript
微信小程序抽奖组件的使用步骤
2021/01/11 Javascript
[03:39]2015国际邀请赛主赛事首日精彩回顾
2015/08/05 DOTA
[01:07:17]EG vs Optic Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
用pickle存储Python的原生对象方法
2017/04/28 Python
Python基于回溯法子集树模板解决数字组合问题实例
2017/09/02 Python
Python使用回溯法子集树模板解决爬楼梯问题示例
2017/09/08 Python
Python pickle模块常用方法代码实例
2020/10/10 Python
css3实现可滑动跳转的分页插件示例
2014/05/08 HTML / CSS
北美大型运动类产品商城:Champs Sports
2017/01/12 全球购物
什么是网络协议
2016/04/07 面试题
期末考试动员演讲稿
2014/01/10 职场文书
餐厅总厨求职信
2014/03/04 职场文书
市场推广策划方案
2014/06/02 职场文书
学习党的群众路线对照检查材料
2014/09/29 职场文书
个人工作总结范文2014
2014/11/07 职场文书
小学教师个人总结
2015/02/05 职场文书
土木工程生产实习心得体会
2016/01/22 职场文书
爱国之歌(8首)
2019/09/29 职场文书
python基于tkinter制作无损音乐下载工具
2021/03/29 Python
如何有效防止sql注入的方法
2021/05/25 SQL Server
eclipse创建项目没有dynamic web的解决方法
2021/06/24 Java/Android
Jmerte 分布式压测及分布式压测配置
2022/04/30 Java/Android