是否可以显示php如何计算问题的解决方案。
例如:
<?php
$equation = (5+1)*3/9; // outputs 2
?>
如果希望查看它处理的所有步骤以获得该解决方案:
IE:
(5+1)=6
6×3=18
18/9=2
最佳答案
简短的回答是“也许”。在运行时不可能像预期的那样钩住php内部。但是,有一种替代方法可以使用外部解析器接近它。
php脚本解析器&抽象语法树(ast)
原因是,php在内部使用抽象语法树(ast)来定义处理步骤,并通过创建更好的二进制表示形式opcache来优化执行,以避免一次又一次地解析和处理相同的脚本。
因此,如果您需要更多地了解php中的处理,可以考虑分析php c源代码:
AST基础:https://github.com/php/php-src/blob/856b63a632c90c0c23ac49b8e51d5e0b45cb0c4a/Zend/zend_ast.c
例如,搜索ast文本,如ZEND_ADD
,ZEND_SUB
,ZEND_MUL
,ZEND_DIV
,add_function
操作员执行:https://github.com/php/php-src/blob/856b63a632c90c0c23ac49b8e51d5e0b45cb0c4a/Zend/zend_operators.c
例如,搜索sub_function
,mul_function
,div_function
,nikic/php-parser
,$equation = (5+1)*3/9; // outputs 2
php脚本中的ast-math.php
还可以使用php重新实现ast解析器,请参见https://github.com/nikic/PHP-Parser。
下面的示例将原始问题的表达式$equation = (5+1)*3/9; // outputs 2
放入专用的int(2)
文件。解析器使用以下cli命令执行:
composer require nikic/php-parser
vendor/bin/php-parse math.php
它将输出
/var/www/developer/
的解析语法树(基本上是对原始问题的回答):====> File math.php:
==> Node dump:
array(
0: Stmt_Expression(
expr: Expr_Assign(
var: Expr_Variable(
name: equation
)
expr: Expr_BinaryOp_Div(
left: Expr_BinaryOp_Mul(
left: Expr_BinaryOp_Plus(
left: Scalar_LNumber(
value: 5
)
right: Scalar_LNumber(
value: 1
)
)
right: Scalar_LNumber(
value: 3
)
)
right: Scalar_LNumber(
value: 9
)
)
)
)
1: Stmt_Nop(
comments: array(
0: // outputs 2
)
)
)
Opcache分析
通过阅读https://nikic.github.io/2017/04/14/PHP-7-Virtual-machine.html(由上面提到的php ast解析器的作者编写)可以找到有关分析php处理的更多信息。然而,这一部分并没有给出这个问题的额外答案——它更多的是概述备选方案以及它们实际揭示的内容。
php -d opcache.enable_cli=1 -d opcache.opt_debug_level=0x10000 math.php
上面在cli上下文中执行的命令启用opcache调试并输出以下内容:
$_main: ; (lines=3, args=0, vars=1, tmps=1)
; (before optimizer)
; /var/www/developer/math.php:1-4
L0: EXT_STMT
L1: ASSIGN CV0($equation) int(2)
L2: RETURN int(1)
上面的调试输出只包含结果
opcache/
而不包含为语法树确定的相应步骤,这一点非常明显,因为优化版本不需要这些步骤。这可以通过查看生成的opCax二进制文件来验证:
php -d opcache.enable_cli=1 -d opcache.opt_debug_level=0x10000 \
-d opcache.file_cache=/var/www/developer/opcache/ \
-d opcache.file_cache_only=1 math.php
hexdump opcache/08202de11af2c60edca0b5438eeefab6/var/www/developer/math.php.bin -C
(我的工作目录是
0x00000250
,它有一个子目录02
)00000210 2f 76 61 72 2f 77 77 77 2f 64 65 76 65 6c 6f 70 |/var/www/develop|
00000220 65 72 2f 6d 61 74 68 2e 70 68 70 00 75 7f 00 00 |er/math.php.u...|
00000230 28 32 60 aa 75 7f 00 00 30 32 60 aa 75 7f 00 00 |(2`.u...02`.u...|
00000240 38 32 60 aa 75 7f 00 00 40 32 60 aa 75 7f 00 00 |82`.u...@2`.u...|
00000250 02 00 00 00 00 00 00 00 04 00 00 00 ff ff ff ff |................| <--
00000260 01 00 00 00 00 00 00 00 04 00 00 00 ff ff ff ff |................|
00000270 e9 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000280 00 00 00 00 00 00 00 00 02 00 00 00 65 08 08 08 |............e...|
00000290 e9 0b 00 00 00 00 00 00 50 00 00 00 00 00 00 00 |........P.......|
000002a0 00 00 00 00 00 00 00 00 02 00 00 00 26 10 01 08 |............&...|
000002b0 e9 0b 00 00 00 00 00 00 10 00 00 00 00 00 00 00 |................|
000002c0 00 00 00 00 ff ff ff ff 04 00 00 00 3e 01 08 08 |............>...|
000002d0 88 02 00 00 00 00 00 00 00 00 00 00 06 02 00 00 |................|
000002e0 cb 5b 29 c4 00 e7 1a 80 08 00 00 00 00 00 00 00 |.[).............|
000002f0 65 71 75 61 74 69 6f 6e 00 32 60 aa 75 7f 00 00 |equation.2`.u...|
上面的hexdump只显示了opcache文件的结尾。标记行中的第一个字节(at
ZEND_MUL
)已包含优化结果5
。对于给定的示例,没有指向运算符(例如1
)的进一步指针,也没有指向整数文本3
、9
、或。因此,常数方程的结果已经直接存储在opcache中。