• Yii2 一个隐藏的小坑,致使我的组件的 bootstrap 方法执行了多次


    昨天,我通过日志打印,发现我的store 组件的bootstrap在初始化的时候被莫名的执行了两次,日志如下:

    原文链接:fecify电商商城

    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()
    最终找到了原因,步骤如下:
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    对于Yii2的方法:yii\helpers\ArrayHelper::merge(); 我们知道,对于数组中key为数字的部分,譬如:

    yii\helpers\ArrayHelper::merge([‘store’,‘view’],[‘log’,‘store’]);
    合并后的结果为 [‘store’,‘log’,‘view’,‘store’] ,而不是 [‘store’,‘log’,‘view’],因此就要出问题了,store会被执行2次

    对于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__);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    我加了下打印,

    foreach ($this->bootstrap as $class) {
       echo $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__); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    然后在调用组件的地方:

    然后在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.'()
    '; } echo '

    ';
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    通过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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    发现我的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',
       ],
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    造成store组件的bootstrap被执行了两次,

    不知道为什么 yii2,不在这里执行一次数组的 array_unique 方法,

    不然配置乱了,在很多地方配置了bootstrap方法,但是又没有注意到,尤其是bootstrap()方法在每次初始化的时候都要执行,造成额外开销,这个小坑,还是得通过打印$config的方式查看。

  • 相关阅读:
    二分查找一看就会,一写就废?
    Ubuntu22.04 LTS+NVIDIA 4090+Cuda12.1+cudnn8.8.1
    策略模式 + 工厂模式 + 门面模式 实现用户多类型支付功能
    考pmp有用么?
    每日一题 2558. 从数量最多的堆取走礼物(简单,heapq)
    28-搭建Keepalived+LVS+Nginx高可用集群负载均衡
    Redis学习笔记(一) 基础数据类型
    mysql源码分析——InnoDB的内存应用整体架构源码
    Python-日志模块
    常用的校验码
  • 原文地址:https://blog.csdn.net/terry_water/article/details/126483426