roave / function-fqn-replacer
将内部函数的相对引用替换为绝对引用
Requires
- php: ^7.1
- roave/better-reflection: dev-master
- symfony/console: ^3.2.1
Requires (Dev)
- humbug/humbug: dev-master
- phpbench/phpbench: ^0.13.0
- phpunit/phpunit: ^5.7.4
- squizlabs/php_codesniffer: ^2.7.1
This package is auto-updated.
Last update: 2022-11-07 01:01:48 UTC
README
此实用程序提供了一种将函数调用中的相对函数引用替换为绝对引用的方法。
理由
如此推特对话和这篇文章所述,PHP在调用时解析相对函数引用。
这相对正常,因为PHP设计上无法决定哪个文件定义了哪个函数,因为所有指令码缓存都是局部于单个脚本,而不是整个项目。
除此之外,PHP只能在全局命名空间中或进行完全限定名(FQN)调用时对内部函数调用进行优化。
以下是一个关于不带和带有FQN引用的call_user_func()
调用的指令码示例
<?php namespace Foo { call_user_func('foo'); }
指令码
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
4 0 E > INIT_NS_FCALL_BY_NAME
1 SEND_VAL_EX 'foo'
2 DO_FCALL 0
5 3 > RETURN 1
<?php namespace Foo { // this is a FQN reference: \call_user_func('foo'); }
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
4 0 E > INIT_USER_CALL 0 'call_user_func', 'foo'
1 DO_FCALL 0
5 2 > RETURN 1
如您所见,INIT_NS_FCALL_BY_NAME
已消失。这是PHP 7及更高版本应用的大量优化之一(更多示例请参阅zend_compile.c)。
基准测试
所有这些都听起来像是一种愚蠢且无意义的微优化,但当涉及到常用和广泛使用的库时,它会产生巨大的影响。
为了更清楚地说明这一点,此包提供了一些基准测试。
只需在此项目内部运行php -n ./vendor/bin/phpbench run --revs=1000 --iterations=10 --warmup=2 --report=aggregate
$ php -n ./vendor/bin/phpbench run --revs=1000 --iterations=10 --warmup=2 --report=aggregate
PhpBench 0.13.0. Running benchmarks.
Using configuration file: FunctionFQNReplacer/phpbench.json
\RoaveBench\FunctionFQNReplacer\AbsoluteFunctionReferenceBench
benchCallUserFuncWithRelativeReferenceI2 P0 [μ Mo]/r: 2.603 2.586 (μs) [μSD μRSD]/r: 0.034μs 1.31%
benchCallUserFuncWithAbsoluteReferenceI2 P0 [μ Mo]/r: 1.767 1.635 (μs) [ benchCallUserFuncWithAbsoluteReferenceR3 I2 P0 [μ Mo]/r: 1.793 1.799 (μs) [μSD μRSD]/r: 0.009μs 0.53%
2 subjects, 6 iterations, 200 revs, 0 rejects
(best [mean mode] worst) = 1.780 [2.198 2.192] 1.800 (μs)
⅀T: 13.190μs μSD/r 0.022μs μRSD/r: 0.916%
suite: 133a2c6cc9c7a295d7b89ff84b2cfff4f39d8935, date: 2016-12-22, stime: 23:10:51
+----------------------------------------+---------+---------+---------+---------+---------+--------+---------+
| subject | best | mean | mode | worst | stdev | rstdev | diff |
+----------------------------------------+---------+---------+---------+---------+---------+--------+---------+
| benchCallUserFuncWithRelativeReference | 2.642μs | 2.729μs | 2.694μs | 2.839μs | 0.062μs | 2.28% | +68.78% |
| benchCallUserFuncWithAbsoluteReference | 1.577μs | 1.617μs | 1.610μs | 1.688μs | 0.029μs | 1.77% | 0.00% |
+----------------------------------------+---------+---------+---------+---------+---------+--------+---------+
如您所见,call_user_func()
与\call_user_func()
之间存在明显的差异。
请随意将基准测试添加到benchmark/
目录。
安装
本项目不是作为依赖项运行的:请将其作为独立程序安装。
composer create-project roave/function-fqn-replacer
用法
请注意,此项目使用nikic/php-parser
的内部代码生成器。这意味着它在重新创建PHP文件源时会破坏您的编码风格。这是一个已知且未解决的问题。
./function-fqn-replacer path/to/project/files path/to/existing/functions another/path/to/existing/functions
第一个参数是要替换FQN引用的目录的路径。
其他参数是函数定义可以找到的路径。工具需要知道这些信息,以避免替换可能不是内部的函数。
替代方案
此工具是在匆忙中构建的,但经过很好的测试,并且基于坚实的基础。然而,由于当前PHP AST解析器的技术限制,它将修改源文件的空白对齐。
如果你不喜欢这些后果,考虑使用nilportugues/php-backslasher
,它已经存在了一段时间,并使用更低级别的令牌替换实现,可以保留空白对齐