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 相关文章推荐
第十一节--重载
Nov 16 PHP
php 无限分类的树类代码
Dec 03 PHP
PHP执行linux系统命令的常用函数使用说明
Apr 27 PHP
PHP几个数学计算的内部函数学习整理
Aug 06 PHP
php 删除一个数组中的某个值.兼容多维数组!
Feb 18 PHP
PHP代码保护--Zend Guard的使用详解
Jun 03 PHP
thinkphp普通查询与表达式查询实例分析
Nov 24 PHP
ThinkPHP安装和设置
Jul 27 PHP
php数据访问之查询关键字
May 09 PHP
php从数据库中获取数据用ajax传送到前台的方法
Aug 20 PHP
Referer原理与图片防盗链实现方法详解
Jul 03 PHP
php实现快速对二维数组某一列进行组装的方法小结
Dec 04 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 xml实例 留言本
2009/03/20 PHP
新浪中用来显示flash的函数
2007/04/02 Javascript
常见效果实现之返回顶部(结合淡入、淡出、减速滚动)
2012/01/04 Javascript
jQuery基本选择器选择元素使用介绍
2013/04/18 Javascript
setTimeout函数兼容各主流浏览器运行执行效果实例
2013/06/13 Javascript
jQuery移动页面开发中的触摸事件与虚拟鼠标事件简介
2015/12/03 Javascript
VC调用javascript的几种方法(推荐)
2016/08/09 Javascript
详解bootstrap用dropdown-menu实现上下文菜单
2017/09/22 Javascript
JavaScript设计模式之构造函数模式实例教程
2018/07/02 Javascript
微信小程序学习笔记之文件上传、下载操作图文详解
2019/03/29 Javascript
[01:11:46]DOTA2-DPC中国联赛 正赛 iG vs Magma BO3 第一场 2月23日
2021/03/11 DOTA
Python中zfill()方法的使用教程
2015/05/20 Python
符合语言习惯的 Python 优雅编程技巧【推荐】
2018/09/25 Python
python发送多人邮件没有展示收件人问题的解决方法
2019/06/21 Python
Python二维码生成识别实例详解
2019/07/16 Python
Django choices下拉列表绑定实例
2020/03/13 Python
解决keras使用cov1D函数的输入问题
2020/06/29 Python
python利用paramiko实现交换机巡检的示例
2020/09/22 Python
Python join()函数原理及使用方法
2020/11/14 Python
viagogo波兰票务平台:演唱会、体育比赛、戏剧门票
2018/04/23 全球购物
39美元购买一副眼镜或太阳镜:39DollarGlasses.com
2018/06/17 全球购物
SCDKey德国:全球领先的数字游戏市场
2019/04/09 全球购物
Unix里面如何在后台运行程序
2016/10/14 面试题
项目资料员岗位职责
2013/12/10 职场文书
放飞蜻蜓反思
2014/02/05 职场文书
家长对老师的评语
2014/04/18 职场文书
桥梁工程专业求职信
2014/04/21 职场文书
运动会宣传口号
2014/06/09 职场文书
2014医学院领导班子对照检查材料思想汇报
2014/09/19 职场文书
2014房屋登记授权委托书
2014/10/13 职场文书
天下第一关导游词
2015/02/06 职场文书
行政主管岗位职责范本
2015/04/09 职场文书
巴黎圣母院读书笔记
2015/06/26 职场文书
门卫管理制度范本
2015/08/05 职场文书
uwsgi+nginx代理Django无法访问静态资源的解决
2021/05/10 Servers
Java Spring读取和存储详细操作
2022/08/05 Java/Android