使用VLD擴展生成Opcode,解決一個奇葩問題

Opcode

Opcode是計算機指令中的一部分,用於指定要執行的操做,指令的格式和規範由處理器的指令規範指定。php

簡而言之,Opcode就是運行在Zend VM中的指令(或者成爲字節碼 Byte Codes)html

Installation

git clone https://github.com/derickr/vld.git vld # 也可使用其餘方式獲取,下面介紹
cd vld
phpize
./configure --with-php-config=/usr/local/php7/bin/php-config --enable-vld # 注意替換本身的路徑
sudo make install
sudo vim /usr/local/php7/etc/php.ini

在 php.ini 增長 extension=vld.so , PHP7本身編譯的須要本身新建php.ini文件
!! 注意 php.ini 中 extension_dir="/usr/local/php7/lib/php/extensions/" 設置的位置git

PECL::Package::vld
Download and Installation Instructionsgithub

Problem

這是在SF的另外一篇博文(面試類型)中出現的,找了一下,沒找到文章。特引用其中一個例子,講解VLD的使用
若是有哪位朋友找到了還請告訴我一聲,我會註上說明,謝謝!面試

看如下栗子shell

$apple = 1;

if (-1) {
    $apple = 2;
}

echo $apple;

相信不少人看到的第一反應是輸出1,這不是很簡單麼?然而並非,輸出的是2(PHP 7.0.4 (cli)) CodePadvim

Why

在安裝好vld擴展以後,咱們立刻就能夠知道是爲何,首先驗證下vld已經安裝php7

php -m | grep vld # 看到輸出一行 vld 就對了

咱們把這個栗子寫到一個test.php(文件名隨意)文件中
test.php
執行如下命令app

php -dvld.active=1 test.php # 參數表示激活vld擴展

輸出應該以下所示,性能

Finding entry points
Branch analysis from position: 0
Jump found. Position 1 = 2, Position 2 = 3
Branch analysis from position: 2
Jump found. Position 1 = -2
Branch analysis from position: 3
filename:       /home/shadowman/test/test.php
function name:  (null)
number of ops:  6
compiled vars:  !0 = $a
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   3     0  E >   ASSIGN                                                   !0, 1
   5     1      > JMPZ                                                     -1, ->3
   6     2    >   ASSIGN                                                   !0, 2
   9     3    >   CONCAT                                           ~3      !0, '%0A'
         4        ECHO                                                     ~3
         5      > RETURN                                                   1

branch: #  0; line:     3-    5; sop:     0; eop:     1; out1:   2; out2:   3
branch: #  2; line:     6-    9; sop:     2; eop:     2; out1:   3
branch: #  3; line:     9-    9; sop:     3; eop:     5; out1:  -2
path #1: 0, 2, 3, 
path #2: 0, 3, 
2

重點內容爲

Opcode Descriptions and Examples

number of ops:  6 # 表示有6個操做
compiled vars:  !0 = $a # 編譯以後的變量, ![number] 表示定義的變量,~[number]表示臨時變量
line     #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
   3     0  E >   ASSIGN                                                   !0, 1
# 以上表示將1這個字面值賦值給!0,即$a
   5     1      > JMPZ                                                     -1, ->3
# 重點!!以上對於 if (-1). opcode解釋爲若是-1爲0,則跳轉到3(Jump to the address if the value is zero)
   6     2    >   ASSIGN                                                   !0, 2
# 以上表示將2這個字面值賦值給!0,即$a
   9     3    >   CONCAT                                           ~3      !0, '%0A'
# 以上表示拼接 !0($a) 和 '%0A'(\n) 賦值給一個臨時變量
         4        ECHO                                                     ~3
# 以上表示輸出 !0($a)
         5      > RETURN                                                   1
# 以上表示返回

能夠很簡單的得知,爲何這裏會有這個奇葩的"錯誤"。

Conclusion

其實vld這個擴展能夠作到更多,好比糾結性能問題,可使用這個擴展儘量的優化你的PHP代碼,或者使用這個擴展排除一些很是隱性的錯誤。

如上!謝謝!

相關文章
相關標籤/搜索