变量处理顺序:PHP7中的更改
随着新的PHP7.0.0的推出,我有点担心所谓“变量”的计算顺序的变化 在上,在“变量处理的更改”下,将显示一个表,其中包含表达式的示例及其在PHP5和PHP7中的处理顺序。列出的四个表达式是:变量处理顺序:PHP7中的更改,php,migration,incompatibility,variable-variables,php-7,Php,Migration,Incompatibility,Variable Variables,Php 7,随着新的PHP7.0.0的推出,我有点担心所谓“变量”的计算顺序的变化 在上,在“变量处理的更改”下,将显示一个表,其中包含表达式的示例及其在PHP5和PHP7中的处理顺序。列出的四个表达式是: $$foo['bar']['baz'] $foo->$bar['baz'] $foo->$bar['baz']() Foo::$bar['baz']() 给定以下字符串和数组: $qux = 'quux'; $foo = array('bar' => array('baz' =>
$$foo['bar']['baz']
$foo->$bar['baz']
$foo->$bar['baz']()
Foo::$bar['baz']()
给定以下字符串和数组:
$qux = 'quux';
$foo = array('bar' => array('baz' => 'qux'));
表$$foo['bar']['baz']
中的第一个表达式在PHP 5中被解释为一个变量的值,该变量名为$foo['bar']['baz']
中的值,因此是$qux
的值
然而,据我所知,在PHP7中,相同的表达式将被解释为$foo
中名为值的变量,因此我希望得到“数组到字符串转换”的PHP通知,因为$foo
是一个数组
表中的其他示例似乎是同一主题的变体
当然,我很好奇为什么PHP7会改变这一点(具体来说,为什么这一改变比向后兼容更重要),但是,这不是一个合适的问题。我的问题更切合实际:
处理这种不兼容的建议方法是什么?
当然,在有问题的表达式中添加大括号会有所帮助(${$foo['bar']['baz']}
,$foo->{$bar['baz']}
,$foo->{$bar['baz']}()
和foo:{$bar['baz']}()
),但这非常麻烦,要遍历大量的旧代码,搜索相对较少的事件
否则,这四个示例是唯一可能的语法变体吗?也就是说,我可以创建一个RegExp和grep
所有有问题的代码吗?可能存在哪些其他变体?
你真的别无选择,只能手工重新考虑它们。除非你能想出一个正则表达式来找出所有变量语法的用法
关于“为什么”。统一变量语法允许我们像使用对象方法的“链接”一样使用数据结构的属性(如数组索引和返回值)
对可变优先顺序的更改是这种增强的牺牲品。在我看来,这是值得的。Rasmus Lerdorf编写了一个静态分析工具,可以发现这些所谓的统一变量语法问题,称为Phan Phan有选项
-b,--backward compatibility checks
来检查潜在的PHP5->PHP7BC问题。使用sed转换代码来解决PHP7统一变量语法问题
您只需找到$
、:$
和->$
的所有实例,并在需要时添加大括号:
find . -name "*.php" -exec grep -l '\->\$' {} \;|while read f; do
echo $f; grep -H '\->\$' $f ;
# do some sed magic here to add braces
done
find . -name "*.php" -exec grep -l '\$\$\w*\[' {} \;|while read f; do
echo $f; grep -H '\$\$\w*\[' $f ;
# do some sed magic here to add braces
done
find . -name "*.php" -exec grep -l '::\$' {} \;|while read f; do
echo $f; grep -H '::\$' $f ;
# do some sed magic here to add braces
done
也许有人知道正确的sed
语法,所以我将在这里添加它
我已经注释掉了对象前面的指针实例&
,其中包含:
find . -name "*.php" -exec grep -l new {} \;|while read f; do
sed -i -e 's~=\s*\&\s*new~= /*\&*/ new~g' "$f">/tmp/a;
done
我添加了注释,而不是仅仅删除&
,以便能够解决以后可能出现的错误。步骤1,查找问题表达式
使用grep
和一些神奇的正则表达式很难找到它,因为它有很多因素
Phan可以解决这个问题,使用选项-b,--backwardcompatibility
检查潜在的PHP5->PHP7BC问题。它可能有点重,因为它寻找共同的问题
如果你想要一个没有配置的工具,你可以试试
PHP迁移
它将两次解析代码,第一次解析为PHP7,第二次解析为PHP5。然后比较AST结果中的节点,如果发现任何差异,则意味着它在PHP5/7之间运行时将发生不同的行为,这样您就可以导航到该工具报告的行并手动检查代码
$ cat demo.php
<?php
$$foo['bar']['baz'];
$foo->$bar['baz'];
$foo->$bar['baz']();
Foo::$bar['baz']();
$ php bin/phpmig demo.php
File: demo.php
--------------------------------------------------------------------------------
Found 4 spot(s), 4 identified
--------------------------------------------------------------------------------
3 | WARNING | * | 7.0.0 | Different behavior between PHP 5/7
4 | WARNING | * | 7.0.0 | Different behavior between PHP 5/7
5 | WARNING | * | 7.0.0 | Different behavior between PHP 5/7
6 | WARNING | * | 7.0.0 | Different behavior between PHP 5/7
--------------------------------------------------------------------------------
$cat demo.php
真的那么麻烦吗?您只需要找到$
和->$
的所有实例,并在需要的地方添加大括号。如果您有比$$foo
更复杂的多个实例,那么您的代码还是有问题。认为这是一个重构的机会。另外,如果你有良好的测试,那么你甚至不需要这样做。看看哪些测试在5.x下失败,哪些测试在7下通过。然后修复您的代码。谢谢Ed Cottrell,您认为只有$$
、->$
和:$
可以查看吗?我还想念哪些人?(我能处理假阳性,那些不太多)。可能会为您确定UV问题,以及其他各种可能的迁移hiccups@MartenKoetsier应该这样做。请注意,::$
将给您带来很多误报,相对于其他错误。另外,仅供参考,如果您使用PHPStorm(或想尝试演示),PHPStorm 10会自动执行大量PHP7兼容性检查。(我没有隶属关系;我只是喜欢这个产品。)不幸的是,Phan需要PHP7+,我还不容易获得它(现在!)。但是,我在他们的源代码中查找了兼容性检查,只找到了对$$var[]
和$foo->$bar['baz']的引用代码>(都在函数visitDim
中的src/Phan/Analyze/BreadthFirstVisitor.php中)。这些是指测试0047和0051。这让我想到搜索$$
和->$
(@Ed Cottrell)确实会奏效!我也在寻找其他的检测手段,但没有积极的结果。也许将来会有一些轻量级的解析器可用。同时,你的回答至少帮助解决了我的问题,所以现在,它被接受了。谢谢,谢谢你的链接。阅读这篇文章有助于我更好地理解它。“为什么”的问题至少得到了回答!最后,我可能真的会手工重构。这方面的主要问题是寻找实例,这可能通过来自Phan的测试得到充分解决。
<?php
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;
// Parse in PHP 5 mode
$parser = (new ParserFactory())->create(ParserFactory::ONLY_PHP5);
$printer = new PrettyPrinter\Standard();
$code = <<<'EOC'
<?php
$$foo['bar']['baz'];
$foo->$bar['baz'];
$foo->$bar['baz']();
Foo::$bar['baz']();
EOC;
$stmts = $parser->parse($code);
$code = $printer->prettyPrintFile($stmts);
echo $code."\n";