昨天,我通过日志打印,发现我的store 组件的bootstrap在初始化的时候被莫名的执行了两次,日志如下:
store (),fecshop\services\Store::actionBootstrap() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/services/Service.php(58),::call_user_func_array() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Service::__call() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(316),fecshop\components\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/web/Application.php(66),yii\base\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(267),yii\web\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Object.php(107),yii\base\Application::init() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(206),yii\base\Object::__construct() /www/web/develop/fecshop/appfront/web/index.php(44),yii\base\Application::__construct() store (),fecshop\services\Store::actionBootstrap() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/services/Service.php(58),::call_user_func_array() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Service::__call() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(316),fecshop\components\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/web/Application.php(66),yii\base\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(267),yii\web\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Object.php(107),yii\base\Application::init() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(206),yii\base\Object::__construct() /www/web/develop/fecshop/appfront/web/index.php(44),yii\base\Application::__construct()
最终找到了原因,步骤如下:
对于Yii2的方法:
yii\helpers\ArrayHelper::merge();
我们知道,对于数组中key为数字的部分,譬如:
yii\helpers\ArrayHelper::merge(['store','view'],['log','store']); 合并后的结果为 ['store','log','view','store'] ,而不是 ['store','log','view']
对于yii2的bootstrap,我写了一个store组件,然后,没有注意到,在两个地方加入了这个配置:
'bootstrap' => ['store'],
bootstrap的执行代码在:
yii\base\Application的bootstrap()方法中,大约298行出的代码:
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__);
}
}
我加了下打印,
foreach ($this->bootstrap as $class) {
echo $class.'<br/>';
$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__);
}
}
然后在调用组件的地方:
然后在Store组件的bootstrap方法中加入
public function bootstrap($app){
$d = debug_backtrace();
foreach($d as $e){
$function = $e['function'];
$class = $e['class'];
$file = $e['file'];
$line = $e['line'];
echo $file.'('.$line.'),'.
$class.'::'.$function.'()<br/>';
}
echo '<br/><br/>';
通过debug_backtrace(),进行打印输出:
结果如下:
debug gii store (),fecshop\services\Store::actionBootstrap() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/services/Service.php(58),::call_user_func_array() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Service::__call() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(316),fecshop\components\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/web/Application.php(66),yii\base\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(267),yii\web\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Object.php(107),yii\base\Application::init() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(206),yii\base\Object::__construct() /www/web/develop/fecshop/appfront/web/index.php(44),yii\base\Application::__construct() store (),fecshop\services\Store::actionBootstrap() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/services/Service.php(58),::call_user_func_array() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Service::__call() /www/web/develop/fecshop/vendor/fancyecommerce/fecshop/components/Store.php(22),fecshop\services\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(316),fecshop\components\Store::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/web/Application.php(66),yii\base\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(267),yii\web\Application::bootstrap() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Object.php(107),yii\base\Application::init() /www/web/develop/fecshop/vendor/yiisoft/yii2/base/Application.php(206),yii\base\Object::__construct() /www/web/develop/fecshop/appfront/web/index.php(44),yii\base\Application::__construct()
发现我的store 组件确实被执行了2次,
原因就是,\appfront\config\fecshop_local.php加入了配置:对store组件的配置
return [
'modules'=>$modules,
'bootstrap' => ['store'],
'services' => $services,
];
在另外一个地方,我也加入了配置:
'modules'=>$modules,
/* only config in front web */
'bootstrap' => ['store'],
'params' => [
/* appfront base theme dir */
'appfrontBaseTheme' => '@fecshop/app/appfront/theme/base/front',
'appfrontBaseLayoutName'=> 'main.php',
],
造成store组件的bootstrap被执行了两次,
不知道为什么yii2,不在这里执行一次数组的array_unique方法,
不然配置乱了,在很多地方配置了bootstrap方法,但是又没有注意到,尤其是bootstrap()方法在每次初始化的时候都要执行,造成额外开销,这个小坑,还是得通过打印$config的方式查看。
还是你架构上的问题
Yii2应该将数组去重一下的。
这是Yii2配置的问题,和我架构有毛关系,乱说。