PHP 7.2将未定义的常量错误从通知升级为警告,并建议以后它们将返回完整错误。
我正在尝试找到一种通过脚本(最好是通过正则表达式)修复这些问题的方法,我可以运行该正则表达式来解析站点上的每个PHP文件,查找所有令人讨厌的代码,并对其进行修复。
我找到了多个示例来解决一个变体,但没有一个解决另一个变体,这就是我正在寻求帮助的一个例子。
这是一个示例文件:
<?php
$array[foo] = "bar";
// this should become
// $array['foo'] = "bar"
echo "hello, my name is $array[foo] and it's nice to meet you";
// would need to become
// echo "hello, my name is " . $array['foo'] . " and it's nice to meet you";
?>
我已经看到了很多用于标识和更改第一种类型的选项,但是对于第二种类型则没有,因为未定义的常量位于字符串中。在那种情况下,解析器将需要:
$array[foo]
替换为$array['foo']
编辑:理想情况下,一个正则表达式可以一遍处理示例代码中的两个示例-即添加对号,并且如果标识在字符串内,则还添加引号/点。
答案 0 :(得分:1)
$array[foo] = "bar"; // this should become // $array['foo'] = "bar"
是的,这始终会触发通知,并且一直是不良做法。
echo "hello, my name is $array[foo] and it's nice to meet you"; // would need to become // echo "hello, my name is " . $array['foo'] . " and it's nice to meet you";
否,此样式从未触发通知,现在也不会触发。实际上,PHP文档中的it's used as an example。 PHP永远不会删除在字符串中插入数组变量的功能。
您的第一个案例很容易抓住这样的东西:
$str = '$array[foo] = "bar";';
echo preg_replace("/(\\$[a-z_][a-z0-9_]*)\\[([a-z][a-z0-9_]*)\\]/", "$1['$2']", $str);
但是当然只需要在字符串之外捕获。
与任何复杂的语法一样,正则表达式永远不会像语法特定的解析器那样可靠。由于您正在解析PHP代码,因此最准确的解决方案是使用PHP's own token parser。
$php = <<< 'PHP'
<?php
$array[foo] = "bar"; // this line should be the only one altered.
$array['bar'] = "baz";
echo "I'm using \"$array[foo]\" and \"$array[bar]\" in a sentence";
echo 'Now I\'m not using "$array[foo]" and "$array[bar]" in a sentence';
PHP;
$tokens = token_get_all($php);
$in_dq_string = false;
$last_token = null;
$output = "";
foreach ($tokens as $token) {
if ($last_token === "[" && is_array($token) && $token[0] === 319 && !$in_dq_string) {
$output .= "'$token[1]'";
} elseif (is_array($token)) {
$output .= $token[1];
} else {
if ($token === "\"") {
$in_dq_string = !$in_dq_string;
}
$output .= $token;
}
$last_token = $token;
}
echo $output;
输出:
<?php
$array['foo'] = "bar"; // this line should be the only one altered.
$array['bar'] = "baz";
echo "I'm using \"$array[foo]\" and \"$array[bar]\" in a sentence";
echo 'Now I\'m not using "$array[foo]" and "$array[bar]" in a sentence';
此代码需要考虑一些边缘情况,例如,当您有意使用常量作为数组索引时。
答案 1 :(得分:0)
这并不完美,但可以安全运行多次(example)
$str = 'echo "hello, my name is $array[foo] and it\'s nice to meet you";';
echo preg_replace_callback('/\".*(\$.*\[[^\'].*[^\']\]).*\"/', function($match) {
$search = ['[', ']'];
$replace = ["['", "']"];
$array = '" . ' . str_replace($search, $replace, $match[1]) . ' . "';
return str_replace($match[1], $array, $match[0]);
}, $str);
正则表达式的作用是将其自身限制为双引号字符串(\"
)。然后,我们寻找$var[val]
,不带记号'
。捕获到它之后,就可以通过执行两阶段str_replace
的回调来运行它。第一个使用匹配的正则表达式将匹配的$var[val]
用双引号引起来并插入刻度线,第二个使用找到的正则表达式匹配项将其插入整个字符串中
它不会做得很好。如果您有$array[foo] $array[bar]
,它将以
" . $array['foo'] . "" . $array['bar'] . "
漂亮,但仍然有效的代码