php 调试利器: debug_backtrace

 

debug_backtrace是一个bug工具,如果加入到某个类函数里面,那么可以看到调用这个函数的类方法,依次上推,直至index.php
下面是我打印的一个yii2组件的日志:

public function actionBootstrap($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/>';

输出的日志为:

(),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 strace 追踪 某个执行的url

在日常的使用yii2,我们有时候想跟踪一下执行加载的各个文件,也就是说,某个url执行后,具体文件的加载,下面所以下具体的方法:

我们使用strace来跟踪url执行,下面是详细步骤:

1.需要更改一下yii2 的库包文件

vendor\yiisoft\yii2\web\Request.php文件 713行左右:

$scriptUrl = $this->getScriptUrl();  
        $baseUrl = $this->getBaseUrl();  
        if (strpos($pathInfo, $scriptUrl) === 0) {  
            $pathInfo = substr($pathInfo, strlen($scriptUrl));  
        } elseif ($baseUrl === '' || strpos($pathInfo, $baseUrl) === 0) {  
            $pathInfo = substr($pathInfo, strlen($baseUrl));  
        } elseif (isset($_SERVER['PHP_SELF']) && strpos($_SERVER['PHP_SELF'], $scriptUrl) === 0) {  
            //$pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl));  
        } else {  
            throw new InvalidConfigException('Unable to determine the path info of the current request.');  
        }

需要注释掉这个,才能通过strace 追踪,不然会丢失 REQUEST_URI ,这段代码会把  $pathInfo 弄成空值。

譬如我要追踪的 url 为: http://10.10.10.252:610/wishorder/product/syncwish

HTTP_HOST=10.10.10.252:610 REQUEST_URI=/wishorder/product/syncwish    strace -s 600 -t -f -o  strace.txt  /usr/local/php/bin/php  /www/web/develop/erp2/backend/web/index.php   >> 22.thml    
-s 代表字符的最大长度,默认是32  
-o 追踪日志到这个文件

然后就可以追踪了,

譬如wish抓取订单api的一段log:(当然,上面的命令,你可以用grep过滤一下,譬如我想要看我执行的某个url,系统加载的文件)

3389  17:27:37 stat("/www/web/develop/erp2/common/lib/Wish/WishRequest.php", {st_mode=S_IFREG|0664, st_size=2967, ...}) = 0  
3389  17:27:37 lstat("/www/web/develop/erp2/common/lib/Wish/WishRequest.php", {st_mode=S_IFREG|0664, st_size=2967, ...}) = 0  
3389  17:27:37 lstat("/www/web/develop/erp2/common/lib/Wish", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0  
3389  17:27:37 lstat("/www/web/develop/erp2/common/lib", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0  
3389  17:27:37 lstat("/www/web/develop/erp2/common", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0  
3389  17:27:37 open("/www/web/develop/erp2/common/lib/Wish/WishRequest.php", O_RDONLY) = 6  
3389  17:27:37 fstat(6, {st_mode=S_IFREG|0664, st_size=2967, ...}) = 0  
3389  17:27:37 fstat(6, {st_mode=S_IFREG|0664, st_size=2967, ...}) = 0  
3389  17:27:37 fstat(6, {st_mode=S_IFREG|0664, st_size=2967, ...}) = 0  
3389  17:27:37 mmap(NULL, 2967, PROT_READ, MAP_SHARED, 6, 0) = 0x7fea6f2fb000  
3389  17:27:37 brk(0x2619000)           = 0x2619000  
3389  17:27:37 munmap(0x7fea6f2fb000, 2967) = 0  
3389  17:27:37 close(6)                 = 0  
3389  17:27:37 rt_sigaction(SIGALRM, NULL, {SIG_DFL, [], 0}, 8) = 0  
3389  17:27:37 rt_sigaction(SIGALRM, {0x3dd300ee40, [], SA_RESTORER, 0x37f96326a0}, NULL, 8) = 0  
3389  17:27:37 alarm(10)                = 0  
3389  17:27:37 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0  
3389  17:27:37 socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP) = 6  
3389  17:27:37 close(6)                 = 0  
3389  17:27:37 socket(PF_NETLINK, SOCK_RAW, 0) = 6  
3389  17:27:37 bind(6, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0  
3389  17:27:37 getsockname(6, {sa_family=AF_NETLINK, pid=3389, groups=00000000}, [12]) = 0  
3389  17:27:37 sendto(6, "\24\0\0\0\26\0\1\3\t\364gV\0\0\0\0\0\0\0\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20  
3389  17:27:37 recvmsg(6, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"0\0\0\0\24\0\2\0\t\364gV=\r\0\0\2\10\200\376\1\0\0\0\10\0\1\0\177\0\0\1\10\0\2\0\177\0\0\1\7\0\3\0lo\0\0<\0\0\0\24\0\2\0\t\364gV=\r\0\0\2\30\200\0\2\0\0\0\10\0\1\0\n\n\n\374\10\0\2\0\n\n\n\374\10\0\4\0\n\n\n\377\t\0\3\0eth0\0\0\0\0\0\0\0\0h)\215n\352\177\0\0\0`\256n\352\177\0\0\2315\323n\352\177\0\0X\7a\3717\0\0\0Hu\322n\352\177\0\0\0\0\0\0\5\0\0\0\37\3\0\0\1\0\0\0\360\20\235\226\377\177\0\0005\0\0\0\0\0\0\0\0\355.o\352\177\0\0\340\21\235\226\377\177\0\0\10\22\235\226\377\177\0\0\250\351.o\352\177\0\0h)\215n\352\177\0\0O\333\235|\0\0\0\0\252\236\340\3707\0\0\0\0\0\0\0\0\0\0\0h)\215n\352\177\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\250\351.o\352\177\0\0\r\0\0\0\0\0\0\0\354X\322n\352\177\0\0\0\0\0\0\0\0\0\0\260\22\235\226\377\177\0\0\0\0\0\0\0\0\0\0\0\355.o\352\177\0\0\220\21\235\226\377\177\0\0\320\22\235\226\377\177\0\0\250\21\235\226\377\177\0\0@\340\322n\1\0\0\0\340\213\322n\352\177\0\0\2315\323n\352\177\0\0\250\351.o\352\177\0\0\0\0\0\0\0\0\0\0008)\215n\352\177\0\0\250\351.o\352\177\0\0Q\20\323n\352\177\0\0000\371\322n\352\177\0\0\310\213\322n\352\177\0\0\0\0\0\0\5\0\0\0\\\1\0\0\1\0\0\0000\371\322n\352\177\0\0@\340\322n\352\177\0\0\0\355.o\352\177\0\0000\207`\3717\0\0\0\0`\256n\352\177\0\0/www/web/develop/erp2/common/lib/Wish/WishRequest.php\0\0\0\0\0\0\0\0\0\0\0\0@\322n\352\177\0\0@\340\340\3707\0\0\0\5\0\0\0\377\177\0\0\0\0\0\0\0\0\0\0\1\0\0\0\352\177\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 108  
3389  17:27:37 recvmsg(6, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"@\0\0\0\24\0\2\0\t\364gV=\r\0\0\n\200\200\376\1\0\0\0\24\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\24\0\6\0\377\377\377\377\377\377\377\377\n\10\0\0\n\10\0\0@\0\0\0\24\0\2\0\t\364gV=\r\0\0\n@\200\375\2\0\0\0\24\0\1\0\376\200\0\0\0\0\0\0\326=~\377\376L\361B\24\0\6\0\377\377\377\377\377\377\377\377\353\10\0\0\353\10\0\0\2315\323n\352\177\0\0X\7a\3717\0\0\0Hu\322n\352\177\0\0\0\0\0\0\5\0\0\0\37\3\0\0\1\0\0\0\360\20\235\226\377\177\0\0005\0\0\0\0\0\0\0\0\355.o\352\177\0\0\340\21\235\226\377\177\0\0\10\22\235\226\377\177\0\0\250\351.o\352\177\0\0h)\215n\352\177\0\0O\333\235|\0\0\0\0\252\236\340\3707\0\0\0\0\0\0\0\0\0\0\0h)\215n\352\177\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\250\351.o\352\177\0\0\r\0\0\0\0\0\0\0\354X\322n\352\177\0\0\0\0\0\0\0\0\0\0\260\22\235\226\377\177\0\0\0\0\0\0\0\0\0\0\0\355.o\352\177\0\0\220\21\235\226\377\177\0\0\320\22\235\226\377\177\0\0\250\21\235\226\377\177\0\0@\340\322n\1\0\0\0\340\213\322n\352\177\0\0\2315\323n\352\177\0\0\250\351.o\352\177\0\0\0\0\0\0\0\0\0\0008)\215n\352\177\0\0\250\351.o\352\177\0\0Q\20\323n\352\177\0\0000\371\322n\352\177\0\0\310\213\322n\352\177\0\0\0\0\0\0\5\0\0\0\\\1\0\0\1\0\0\0000\371\322n\352\177\0\0@\340\322n\352\177\0\0\0\355.o\352\177\0\0000\207`\3717\0\0\0\0`\256n\352\177\0\0/www/web/develop/erp2/common/lib/Wish/WishRequest.php\0\0\0\0\0\0\0\0\0\0\0\0@\322n\352\177\0\0@\340\340\3707\0\0\0\5\0\0\0\377\177\0\0\0\0\0\0\0\0\0\0\1\0\0\0\352\177\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 128  
3389  17:27:37 recvmsg(6, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\24\0\0\0\3\0\2\0\t\364gV=\r\0\0\0\0\0\0\1\0\0\0\24\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\24\0\6\0\377\377\377\377\377\377\377\377\n\10\0\0\n\10\0\0@\0\0\0\24\0\2\0\t\364gV=\r\0\0\n@\200\375\2\0\0\0\24\0\1\0\376\200\0\0\0\0\0\0\326=~\377\376L\361B\24\0\6\0\377\377\377\377\377\377\377\377\353\10\0\0\353\10\0\0\2315\323n\352\177\0\0X\7a\3717\0\0\0Hu\322n\352\177\0\0\0\0\0\0\5\0\0\0\37\3\0\0\1\0\0\0\360\20\235\226\377\177\0\0005\0\0\0\0\0\0\0\0\355.o\352\177\0\0\340\21\235\226\377\177\0\0\10\22\235\226\377\177\0\0\250\351.o\352\177\0\0h)\215n\352\177\0\0O\333\235|\0\0\0\0\252\236\340\3707\0\0\0\0\0\0\0\0\0\0\0h)\215n\352\177\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\0\0\0\0\250\351.o\352\177\0\0\r\0\0\0\0\0\0\0\354X\322n\352\177\0\0\0\0\0\0\0\0\0\0\260\22\235\226\377\177\0\0\0\0\0\0\0\0\0\0\0\355.o\352\177\0\0\220\21\235\226\377\177\0\0\320\22\235\226\377\177\0\0\250\21\235\226\377\177\0\0@\340\322n\1\0\0\0\340\213\322n\352\177\0\0\2315\323n\352\177\0\0\250\351.o\352\177\0\0\0\0\0\0\0\0\0\0008)\215n\352\177\0\0\250\351.o\352\177\0\0Q\20\323n\352\177\0\0000\371\322n\352\177\0\0\310\213\322n\352\177\0\0\0\0\0\0\5\0\0\0\\\1\0\0\1\0\0\0000\371\322n\352\177\0\0@\340\322n\352\177\0\0\0\355.o\352\177\0\0000\207`\3717\0\0\0\0`\256n\352\177\0\0/www/web/develop/erp2/common/lib/Wish/WishRequest.php\0\0\0\0\0\0\0\0\0\0\0\0@\322n\352\177\0\0@\340\340\3707\0\0\0\5\0\0\0\377\177\0\0\0\0\0\0\0\0\0\0\1\0\0\0\352\177\0\0"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 20  
3389  17:27:37 close(6)                 = 0  
3389  17:27:37 open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 6  
3389  17:27:37 fstat(6, {st_mode=S_IFREG|0644, st_size=178, ...}) = 0  
3389  17:27:37 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fea6f2fb000  
3389  17:27:37 read(6, "127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4\n10.10.10.252 grande\n::1         localhost localhost.localdomain localhost6 localhost6.localdomain6\n", 4096) = 178  
3389  17:27:37 read(6, "", 4096)        = 0  
3389  17:27:37 close(6)                 = 0  
3389  17:27:37 munmap(0x7fea6f2fb000, 4096) = 0  
3389  17:27:37 open("/usr/local/lib/libnss_dns.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)  
3389  17:27:37 open("/usr/local/mysql/lib/libnss_dns.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)  
3389  17:27:37 open("/etc/ld.so.cache", O_RDONLY) = 6  
3389  17:27:37 fstat(6, {st_mode=S_IFREG|0644, st_size=50231, ...}) = 0  
3389  17:27:37 mmap(NULL, 50231, PROT_READ, MAP_PRIVATE, 6, 0) = 0x7fea663ec000  
3389  17:27:37 close(6)                 = 0  
3389  17:27:37 open("/lib64/libnss_dns.so.2", O_RDONLY) = 6  
3389  17:27:37 read(6, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\20\0\0\0\0\0\0@\0\0\0\0\0\0\0\340b\0\0\0\0\0\0\0\0\0\0@\0008\0\t\0@\0!\0 \0\6\0\0\0\5\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0\370\1\0\0\0\0\0\0\370\1\0\0\0\0\0\0\10\0\0\0\0\0\0\0\3\0\0\0\4\0\0\0\260D\0\0\0\0\0\0\260D\0\0\0\0\0\0\260D\0\0\0\0\0\0\34\0\0\0\0\0\0\0\34\0\0\0\0\0\0\0\20\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\254I\0\0\0\0\0\0\254I\0\0\0\0\0\0\0\0 \0\0\0\0\0\1\0\0\0\6\0\0\0\300M\0\0\0\0\0\0\300M \0\0\0\0\0\300M \0\0\0\0\0(\3\0\0\0\0\0\0008\3\0\0\0\0\0\0\0\0 \0\0\0\0\0\2\0\0\0\6\0\0\0\360M\0\0\0\0\0\0\360M \0\0\0\0\0\360M \0\0\0\0\0\320\1\0\0\0\0\0\0\320\1\0\0\0\0\0\0\10\0\0\0\0\0\0\0\4\0\0\0\4\0\0\0008\2\0\0\0\0\0\0008\2\0\0\0\0\0\0008\2\0\0\0\0\0\0D\0\0\0\0\0\0\0D\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0P\345td\4\0\0\0\314D\0\0\0\0\0\0\314D\0\0\0\0\0\0\314D\0\0\0\0\0\0l\0\0\0\0\0\0\0l\0\0\0\0\0\0\0\4\0\0\0\0\0\0\0Q\345td\6\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\10\0\0\0\0\0\0\0R\345td\4\0\0\0\300M\0\0\0\0\0\0\300M \0\0\0\0\0\300M \0\0\0\0\0@\2\0\0\0\0\0\0@\2\0\0\0\0\0\0\1\0\0\0\0\0\0\0\4\0\0\0\24\0\0\0\3\0\0\0GNU\0v\214\234\260?\257fS\327\"\234\340-\264pw"..., 832) = 832  
3389  17:27:37 fstat(6, {st_mode=S_IFREG|0755, st_size=27424, ...}) = 0  
3389  17:27:37 mmap(NULL, 2117880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 6, 0) = 0x7fea65bca000  
3389  17:27:37 mprotect(0x7fea65bcf000, 2093056, PROT_NONE) = 0  
3389  17:27:37 mmap(0x7fea65dce000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 6, 0x4000) = 0x7fea65dce000  
3389  17:27:37 close(6)                 = 0  
3389  17:27:37 mprotect(0x7fea65dce000, 4096, PROT_READ) = 0  
3389  17:27:37 munmap(0x7fea663ec000, 50231) = 0  
3389  17:27:37 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 6  
3389  17:27:37 connect(6, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, 16) = 0  
3389  17:27:37 poll([{fd=6, events=POLLOUT}], 1, 0) = 1 ([{fd=6, revents=POLLOUT}])  
3389  17:27:37 sendto(6, "\370\23\1\0\0\1\0\0\0\0\0\0\10merchant\4wish\3com\0\0\1\0\1", 35, MSG_NOSIGNAL, NULL, 0) = 35  
3389  17:27:37 poll([{fd=6, events=POLLIN|POLLOUT}], 1, 5000) = 1 ([{fd=6, revents=POLLOUT}])  
3389  17:27:37 sendto(6, "\373\275\1\0\0\1\0\0\0\0\0\0\10merchant\4wish\3com\0\0\34\0\1", 35, MSG_NOSIGNAL, NULL, 0) = 35  
3389  17:27:37 poll([{fd=6, events=POLLIN}], 1, 4998) = 1 ([{fd=6, revents=POLLIN}])  
3389  17:27:37 ioctl(6, FIONREAD, [186]) = 0  
3389  17:27:37 recvfrom(6, "\373\275\201\200\0\1\0\1\0\1\0\0\10merchant\4wish\3com\0\0\34\0\1\300\f\0\5\0\1\0\0\1+\0:\37merchantfrontendproxy-842303458\tus-west-1\3elb\tamazonaws\300\32\300O\0\6\0\1\0\0\0;\0E\6ns-699\tawsdns-23\3net\0\21awsdns-hostmaster\6amazon\300\32\0\0\0\1\0\0\34 \0\0\3\204\0\22u\0\0\0\0<", 2048, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("8.8.8.8")}, [16]) = 186  
3389  17:27:37 poll([{fd=6, events=POLLIN}], 1, 4749

 

 

 

 

 

 

 

 

 

 

 

 

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

昨天,我通过日志打印,发现我的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的方式查看。