Blog tvlooy

Dumping PHP opcodes

php, opcodes, vld, pickle | September 11, 2015

When parsing PHP files, the Zend Engine generates a series of operation codes, execution units commonly known as "opcodes", representing the function of the code. So how do you dump these opcodes?

PHP has the Vulcan Logic Disassembler (vld) extension. The vld hooks into the Zend Engine and dumps all the opcodes of a script.

Installing vld

Pickle is a new PHP extension installer. It is based on Composer and the plan is to get Composer to fully support it. Very promising! Plus, Pickle fully supports existing PECL extensions. The Github repository has a link to the Pickle PHAR file.

$ sudo pickle.phar install vld - Installing vld (latest-stable) Downloading: 100% +-----------------------------------+--------+ | Package name | vld | | Package version (current release) | 0.13.0 | | Package status | beta | +-----------------------------------+--------+

Next, enable the extension (on Debian based systems):

$ echo 'extension=vld.so' | sudo tee /etc/php5/mods-available/vld.ini $ sudo php5enmod vld

Dumping opcodes

I have 2 test PHP files that have the same functionality. Only, one uses an internal PHP function and the other doesn't. Examples:

$ cat test1.php <?php echo '----------';

$ cat test2.php <?php echo str_repeat('-', 10);

Let's look at the opcodes!

$ php -d vld.active=1 -d vld.execute=0 -f test1.php Finding entry points Branch analysis from position: 0 Jump found. Position 1 = -2 filename: /home/tvl/Desktop/test1.php function name: (null) number of ops: 2 compiled vars: none line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 1 0 E > ECHO '----------' 2 1 > RETURN 1 branch: # 0; line: 1- 2; sop: 0; eop: 1; out1: -2 path #1: 0,

$ php -d vld.active=1 -d vld.execute=0 -f test2.php Finding entry points Branch analysis from position: 0 Jump found. Position 1 = -2 filename: /home/tvl/Desktop/test2.php function name: (null) number of ops: 5 compiled vars: none line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 1 0 E > SEND_VAL '-' 1 SEND_VAL 10 2 DO_FCALL 2 $0 'str_repeat' 3 ECHO $0 2 4 > RETURN 1 branch: # 0; line: 1- 2; sop: 0; eop: 4; out1: -2 path #1: 0,

What's next?

Now that you know how to dump opcodes, you can do all kinds of important stuff like, show people why print is slower than echo, or benchmark whether a for loop is faster or slower than a while loop. Or, compare PHP5 with PHP7. The vld extension working on PHP7.

Kidding aside, if you are interested in this subject, I encourage you to read the PHP Internals Book and the PHP.net internals documentation.