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)组件(如果有)。
- 加载扩展清单文件(extension manifest file)
总体来说就是:配置参数,配置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)
这样就可以了。