5

随着新的 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'));

表中的第一个表达式在$$foo['bar']['baz']PHP 5 中被解释为一个名为 in 的变量的值$foo['bar']['baz'],因此是 的值$qux,即 'quux'

但是,据我了解,在 PHP 7 中,相同的表达式将被解释为名为 in 的值的变量$foo,因此我希望 PHP 通知用于“数组到字符串转换”,因为$foo它是一个数组。

表中的其他示例似乎是同一主题的变体。

当然我很好奇为什么在 PHP 7 中改变了这一点(具体来说,为什么这个改变比向后兼容更重要),但是,这对于 SO 来说不是一个合适的问题。我的问题更实际:

应对这种不兼容性的推荐方法是什么?

当然,在有问题的表达式中添加花括号会有所帮助(${$foo['bar']['baz']}、、$foo->{$bar['baz']}和) $foo->{$bar['baz']}()Foo::{$bar['baz']}()但这非常麻烦,要遍历大量旧代码,搜索相对较少的出现...

否则,这四个示例是唯一可能的语法变化吗?也就是说,我可以创建一个正则表达式和grep所有有问题的代码吗?可能存在哪些其他变体?

4

4 回答 4

5

Rasmus Lerdorf 编写了一个静态分析工具,可以发现这些所谓的统一变量语法问题,称为Phan https://github.com/etsy/phan

Phan 可以选择-b, --backward-compatibility-checks检查潜在的 PHP 5 -> PHP 7 BC 问题。

于 2015-12-04T16:33:08.150 回答
0

第一步,寻找问题表达

使用和一些神奇的正则表达式很难找到grep,因为它有很多因素。

Phan https://github.com/etsy/phan可以解决它,-b, --backward-compatibility它可以检查潜在的 PHP 5 -> PHP 7 BC 问题。它可能有点重,因为它寻找常见问题。

如果你想要一个没有配置的工具,你可以试试

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";
于 2016-09-10T17:14:40.577 回答
0

转换您的代码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

我添加了注释而不是仅仅删除&, 以便能够解决以后可能发生的错误。

于 2016-07-22T07:38:21.693 回答
0

https://wiki.php.net/rfc/uniform_variable_syntax

您实际上别无选择,只能手动重新考虑它们。除非你能想出一个正则表达式来查找所有使用变量的变量语法。

关于“为什么”的原因。统一的变量语法允许我们使用数据结构的属性(如数组索引和返回值),就像我们使用对象方法的“链接”一样。

对可变变量优先顺序的更改是此增强功能的牺牲品。在我看来值得。

于 2015-12-04T16:13:18.910 回答