How to get opcodes of PHP?

  <?php
$show_value   = 123;
echo 'sing_quote'.$show_value;
echo "double_quote{$show_value}";


?>

Its opcode is:

1: <?php
2: $show_value   = 123;
0  ASSIGN              !0, 123
3: echo 'sing_quote'.$show_value;
1  CONCAT              'sing_quote', !0 =>RES[~1]
2  ECHO                ~1
4: echo "double_quote{$show_value}";
3  ADD_STRING          'double_quote' =>RES[~2]
4  ADD_VAR             ~2, !0 =>RES[~2]
5  ECHO                ~2
6  RETURN              1
13650 次浏览

Check out the Vulcan Logic Disassembler PECL extension - see author's home page for more info.

The Vulcan Logic Disassembler hooks into the Zend Engine and dumps all the opcodes (execution units) of a script. It was written as as a beginning of an encoder, but I never got the time for that. It can be used to see what is going on in the Zend Engine.

Once installed, you can use it like this:

php -d vld.active=1 -d vld.execute=0 -f yourscript.php

See also this interesting blog post on opcode extraction, and the PHP manual page listing the available opcodes.

Parsekit has parsekit_compile_string().

sudo pecl install parsekit
var_dump(parsekit_compile_string(<<<PHP
\$show_value   = 123;
echo 'sing_quote'.\$show_value;
echo "double_quote{\$show_value}";
PHP
));

The output is quite verbose, so you'd need to process it to get assembler-like format.

["opcodes"]=>
array(10) {
[0]=>
array(9) {
["address"]=>
int(44682716)
["opcode"]=>
int(101)
["opcode_name"]=>
string(13) "ZEND_EXT_STMT"
["flags"]=>
int(4294967295)
["result"]=>
array(8) {
["type"]=>
int(8)
["type_name"]=>
string(9) "IS_UNUSED"
["var"]=>
int(0)
["opline_num"]=>
string(1) "0"
["op_array"]=>
string(1) "0"
["jmp_addr"]=>
string(1) "0"
["jmp_offset"]=>
string(8) "35419039"
["EA.type"]=>
int(0)
}
["op1"]=>
array(8) {
["type"]=>
int(8)
["type_name"]=>
string(9) "IS_UNUSED"
["var"]=>
int(0)
["opline_num"]=>
string(1) "0"
["op_array"]=>
string(1) "0"
["jmp_addr"]=>
string(1) "0"
["jmp_offset"]=>
string(8) "35419039"
["EA.type"]=>
int(0)
}

You can run code and also see the opcodes if you use https://3v4l.org/

Note: It automatically shows the Vulcan Logic Disassembler (VLD) output, but only if you have "all supported versions" selected in the version dropdown.

Here's a simple example (shown below for posterity): https://3v4l.org/Gt8fd/vld

Code:

<?php
$arr = [1, 2, 3, 4];
print_r(array_map(fn(int $i): int => $i * $i, $arr));

Result:

Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/Gt8fd
function name:  (null)
number of ops:  10
compiled vars:  !0 = $arr
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
2     0  E >   ASSIGN                                                   !0, <array>
3     1        INIT_FCALL                                               'print_r'
2        INIT_FCALL                                               'array_map'
3        DECLARE_LAMBDA_FUNCTION                                  '%00%7Bclosure%7D%2Fin%2FGt8fd%3A3%240'
4        SEND_VAL                                                 ~2
5        SEND_VAR                                                 !0
6        DO_ICALL                                         $3
7        SEND_VAR                                                 $3
8        DO_ICALL
9      > RETURN                                                   1


Function %00%7Bclosure%7D%2Fin%2FGt8fd%3A3%240:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename:       /in/Gt8fd
function name:  {closure}
number of ops:  6
compiled vars:  !0 = $i
line      #* E I O op                           fetch          ext  return  operands
-------------------------------------------------------------------------------------
0  E >   RECV                                             !0
1        MUL                                              ~1      !0, !0
2        VERIFY_RETURN_TYPE                                       ~1
3      > RETURN                                                   ~1
4*       VERIFY_RETURN_TYPE
5*     > RETURN                                                   null


End of function %00%7Bclosure%7D%2Fin%2FGt8fd%3A3%240


Generated using Vulcan Logic Dumper, using php 8.0.0

Two options are, setting opcache.opt_debug_level INI setting or using phpdbg binary provided in a debug-enabled PHP environment (e.g. requiring you to either compile PHP from source or install the related package on Linux).

For more information and a full guide, refer to this php.watch article (also credits to this article).