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的计数器程序
Oct 09 PHP
linux php mysql数据库备份实现代码
Mar 10 PHP
php 定义404页面的实现代码
Nov 19 PHP
深入PHP数据缓存的使用说明
May 10 PHP
thinkphp数据查询和遍历数组实例
Nov 28 PHP
PHP简单判断字符串是否包含另一个字符串的方法
Mar 25 PHP
ThinkPHP中create()方法自动验证实例
Apr 26 PHP
深入理解 PHP7 中全新的 zval 容器和引用计数机制
Oct 15 PHP
PHP PDOStatement::fetchColumn讲解
Jan 31 PHP
thinkphp5框架API token身份验证功能示例
May 21 PHP
laravel 去掉index.php伪静态的操作方法
Oct 12 PHP
php传值和传引用的区别点总结
Nov 19 PHP
Laravel框架分页实现方法分析
Jun 12 #PHP
php 可变函数使用小结
Jun 12 #PHP
PHP程序员学习使用Swoole的理由
Jun 24 #PHP
PHP实现的装箱算法示例
Jun 23 #PHP
PHP基于curl模拟post提交json数据示例
Jun 22 #PHP
PHP获取日期对应星期、一周日期、星期开始与结束日期的方法
Jun 22 #PHP
PHP实现将base64编码字符串转换成图片示例
Jun 22 #PHP
You might like
VOLVO车载收音机
2021/03/02 无线电
php在字符串中查找另一个字符串
2008/11/19 PHP
phpExcel中文帮助手册之常用功能指南
2014/08/18 PHP
JS模拟多线程
2007/02/07 Javascript
在JQuery dialog里的服务器控件 事件失效问题
2010/12/08 Javascript
用JS控制回车事件的代码
2011/02/20 Javascript
jQuery插件的写法分享
2013/06/12 Javascript
给事件响应函数传参数的四种方式小结
2013/12/05 Javascript
JS实现表格数据各种搜索功能的方法
2015/03/03 Javascript
jQuery中inArray方法注意事项分析
2016/01/25 Javascript
JS弹出窗口的运用与技巧大全
2016/11/01 Javascript
AngularJS学习笔记之表单验证功能实例详解
2017/07/06 Javascript
JS 实现缓存算法的示例(FIFO/LRU)
2018/03/20 Javascript
angular2路由之routerLinkActive指令【推荐】
2018/05/30 Javascript
微信小程序地图(map)组件点击(tap)获取经纬度的方法
2019/01/10 Javascript
微信小程序实现Swiper轮播图效果
2019/11/22 Javascript
js实现网页随机验证码
2020/10/19 Javascript
[02:50]【扭转乾坤,只此一招】DOTA2永雾林渊版本开启新篇章
2020/12/22 DOTA
Pyhton中单行和多行注释的使用方法及规范
2016/10/11 Python
python的文件操作方法汇总
2017/11/10 Python
Python 利用pydub库操作音频文件的方法
2019/01/09 Python
Python3.5面向对象与继承图文实例详解
2019/04/24 Python
python批量爬取下载抖音视频
2019/06/17 Python
django表单的Widgets使用详解
2019/07/22 Python
Python bytes string相互转换过程解析
2020/03/05 Python
Python几种常见算法汇总
2020/06/02 Python
Html5 APP中监听返回事件处理的方法示例
2018/03/15 HTML / CSS
俄罗斯商务邀请函
2014/01/26 职场文书
档案信息化建设方案
2014/05/16 职场文书
基层党员对照检查材料
2014/08/25 职场文书
企业员工爱岗敬业演讲稿
2014/08/26 职场文书
学校总务处领导干部个人对照检查材料思想汇报
2014/10/06 职场文书
张丽莉观后感
2015/06/16 职场文书
小学学习委员竞选稿
2015/11/20 职场文书
党章党规党纪学习心得体会
2016/01/14 职场文书
总结高并发下Nginx性能如何优化
2021/11/01 Servers