提问人:Marten Koetsier 提问时间:12/4/2015 更新时间:9/11/2016 访问量:2523
变量处理顺序:PHP 7 中的更改
Variable variables handling order: changes in PHP 7
问:
随着新的 PHP 7.0.0 的发布,我有点担心所谓的“变量”的计算顺序的变化。
在此页面上,在“变量处理的更改”下,显示了一个表格,其中包含 PHP 5 和 PHP 7 中表达式的处理顺序示例。列出的四个表达式是:
$$foo['bar']['baz']
$foo->$bar['baz']
$foo->$bar['baz']()
Foo::$bar['baz']()
给定以下字符串和数组:
$qux = 'quux';
$foo = array('bar' => array('baz' => 'qux'));
表中的第一个表达式在 PHP 5 中被解释为一个名为 中的值的变量的值,因此 的值为 。$$foo['bar']['baz']
$foo['bar']['baz']
$qux
'quux'
然而,在 PHP 7 中,据我了解,相同的表达式将被解释为一个名为 中的值的变量,因此我希望 PHP 通知“数组到字符串的转换”,因为是一个数组。$foo
$foo
表中的其他示例似乎是同一主题的变体。
当然,我很好奇为什么在 PHP 7 中会更改此更改(具体来说,为什么此更改比向后兼容更重要),但是,这对 SO 来说不是一个合适的问题。我的问题更实际:
处理这种不相容性的推荐方法是什么?
当然,在有问题的表达式中添加大括号会有所帮助(、 和 ),但这非常麻烦,要浏览大量旧代码,搜索相对较少的出现次数......${$foo['bar']['baz']}
$foo->{$bar['baz']}
$foo->{$bar['baz']}()
Foo::{$bar['baz']}()
否则,这四个示例是唯一可能的语法变体吗?也就是说,我可以创建一个正则表达式和所有违规代码吗?可能还存在哪些其他变化?grep
答:
https://wiki.php.net/rfc/uniform_variable_syntax
你真的别无选择,只能手动重构它们。除非你能想出一个正则表达式来找到变量变量语法的所有用法。
关于“为什么”的原因。统一变量语法允许我们使用数据结构的属性(如数组索引和返回值),就像我们使用对象方法的“链接”一样。
对可变变量优先顺序的更改是这种增强的牺牲品。在我看来是值得的。
评论
拉斯穆斯·勒多夫(Rasmus Lerdorf)编写了一个静态分析工具,可以发现这些所谓的统一变量语法问题,称为Phan https://github.com/etsy/phan
Phan 可以选择检查潜在的 PHP 5 -> PHP 7 BC 问题。-b, --backward-compatibility-checks
评论
$$var[]
$foo->$bar['baz'];
visitDim
$$
->$
转换您的代码以解决 PHP7 统一变量语法问题sed
您只需要找到 的所有实例,并在需要的地方添加大括号:$$
::$
->$
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 https://github.com/etsy/phan 可以解决这个问题,可以选择检查潜在的 PHP 5 -> PHP 7 BC 问题。它可能有点重,因为它寻找常见问题。-b, --backward-compatibility
如果您想要一个无需配置的工具,您可以尝试
PHP-迁移 https://github.com/monque/PHP-Migration。
它将解析两次代码,第一次是 PHP 7,第二次是 PHP 5。然后比较 AST 结果中的节点,如果发现任何差异,则意味着它在 PHP 5/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
--------------------------------------------------------------------------------
第 2 步,修复它
现在,您有一个列表,其中包含应修复的文件和行号。
1、手动修复,测试慎重推荐
2、通过PHP-Parser PrettyPrinter生成代码
<?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";
上一个:变量:何时有用?[复制]
评论
$$
->$
$$foo
$$
->$
::$
::$