yii2 初始化的bootstrap过程 -引导

bootstrap是指应用开始解析并处理请求之前,一个预先准备环境的阶段,也就是一个前期的初始化 过程,也就是说,在执行helloworld之前,需要执行的代码部分。

启动这个过程会在两个地方,一个是index.php的入口文件,一个是application的bootstrap过程。

1.index.php入口文件: 大致为composer文件自动加载器,yii的文件自动加载器,已经配置文件的合并,环境参数的设置。然后通过\yii\base\application->run()方法创建一个应用主体application。

2.

  • 调用 yii\base\Application::preInit()(预初始化)方法,配置一些高优先级的应用属性,比如 yii\base\Application::basePath 属性。
  • 注册yii\base\Application::errorHandler。
  • 通过给定的应用配置初始化应用的各属性。
  • 通过调用 yii\base\Application::init()(初始化)方法,它会顺次调用 yii\base\Application::bootstrap() 从而运行引导组件。
    • 加载扩展清单文件(extension manifest file) vendor/yiisoft/extensions.php
    • 创建并运行各个扩展声明的 引导组件(bootstrap components)。
    • 创建并运行各个 应用组件 以及在应用的 Bootstrap 属性中声明的各个 模块(modules)组件(如果有)。

总体来说就是:配置参数,配置error的处理,然后执行application的bootstrap()方法

application的bootstrap方法依次:

1.加载插件配置,也就是文件:@vendor/yiisoft/extensions.php中的bootstrap配置,

2.配置的组件(component)和模块的bootstrap配置。

application的bootstrap代码如下:

protected function bootstrap()
   {
       if ($this->extensions === null) {
           $file = Yii::getAlias('@vendor/yiisoft/extensions.php');
           $this->extensions = is_file($file) ? include($file) : [];
       }
       foreach ($this->extensions as $extension) {
           if (!empty($extension['alias'])) {
               foreach ($extension['alias'] as $name => $path) {
                   Yii::setAlias($name, $path);
               }
           }
           if (isset($extension['bootstrap'])) {
               $component = Yii::createObject($extension['bootstrap']);
               if ($component instanceof BootstrapInterface) {
                   Yii::trace('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
                   $component->bootstrap($this);
               } else {
                   Yii::trace('Bootstrap with ' . get_class($component), __METHOD__);
               }
           }
       }

       foreach ($this->bootstrap as $class) {
           $component = null;
           if (is_string($class)) {
               if ($this->has($class)) {
                   $component = $this->get($class);
               } elseif ($this->hasModule($class)) {
                   $component = $this->getModule($class);
               } elseif (strpos($class, '\\') === false) {
                   throw new InvalidConfigException("Unknown bootstrapping component ID: $class");
               }
           }
           if (!isset($component)) {
               $component = Yii::createObject($class);
           }

           if ($component instanceof BootstrapInterface) {
               Yii::trace('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
               $component->bootstrap($this);
           } else {
               Yii::trace('Bootstrap with ' . get_class($component), __METHOD__);
           }
       }
   }

先执行extensions的,在一次执行在bootstrap中的配置,按照配置的顺序依次执行

2.1:在插件扩展中加入bootstrap

'fancyecommerce/fec' => 
 array (
   'name' => 'fancyecommerce/fec',
   'version' => '1.1.2.1',
   'bootstrap' => array
   'alias' => 
   array (
     '@fec' => $vendorDir . '/fancyecommerce/fec',
   ),
   'bootstrap': 'fecadmin\\mywidget\\MyBootstrapClass'
 ),
namespace fecadmin\mywidget;

use yii\base\BootstrapInterface;
use yii\base\Application;

class MyBootstrapClass implements BootstrapInterface
{
    public function bootstrap($app)
    {
        $app->on(Application::EVENT_BEFORE_REQUEST, function () {
             // do something here
        });
    }
}

这样就会在bootstrap过程中执行这个类里面的bootstrap()方法:

参考文献:http://www.yiiframework.com/doc-2.0/guide-structure-extensions.html#bootstrapping-classes,在这里可以查看如何在插件制作的时候在composer.json中进行配置,配置后的内容将被写入extensions.php文件中。

2.2 在模块中加入bootstrap配置

如果是模块,则执行模块对应的Module文件,

$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = 'yii\gii\Module';

上面的配置,配置了模块 gii,并且把gii加入了bootstrap,因此,就会执行\yii\gii\Module->bootstrap();

gii的bootstrap()为:

class Module extends \yii\base\Module implements BootstrapInterface
{
public function bootstrap($app)
   {
       if ($app instanceof \yii\web\Application) {
           $app->getUrlManager()->addRules([
               $this->id => $this->id . '/default/index',
               $this->id . '/<id:\w+>' => $this->id . '/default/view',
               $this->id . '/<controller:[\w\-]+>/<action:[\w\-]+>' => $this->id . '/<controller>/<action>',
           ], false);
       } elseif ($app instanceof \yii\console\Application) {
           $app->controllerMap[$this->id] = [
               'class' => 'yii\gii\console\GenerateController',
               'generators' => array_merge($this->coreGenerators(), $this->generators),
               'module' => $this,
           ];
       }
   }

修改app对应的UrlManager 和controllerMap。

需要注意的是要想bootstrap()执行,一定要实现BootstrapInterface接口,否则,不会被执行,因为在Application->bootstrap函数中有一个判断:

if ($component instanceof BootstrapInterface) {

      Yii::trace('Bootstrap with ' . get_class($component) . '::bootstrap()', __METHOD__);
      $component->bootstrap($this);
}

 

2.3 如果该配置是组件,则执行组件文件对应的class里面的bootstrap方法

同样,和上面的module类型,需要做的是:

2.3.1 在config.php中加入配置,譬如log:

'bootstrap' => ['log'],

2.3.2 让组件所在的class实现接口:use yii\base\BootstrapInterface;

2.3.3  在组件所在的class实现方法bootstrap($app)

这样就可以了。

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注