如何在同一个文件中为 PHP 的多个版本编码而不会出错?

How can I code for multiple versions of PHP in the same file without error?

我尝试使用 version_compare 在一个文件中支持某些 PHP 代码的两个版本,但我仍然遇到错误。

代码:

if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
    $alias = preg_replace_callback('/&#x([0-9a-f]{1,7});/i', function($matches) { return chr(hexdec($matches[1])); }, $alias);
    $alias = preg_replace_callback('/&#([0-9]{1,7});/', function($matches) { return chr($matches[1]); }, $alias);
} else {
    $alias = preg_replace('/&#x([0-9a-f]{1,7});/ei', 'chr(hexdec("\1"))', $alias);
    $alias = preg_replace('/&#([0-9]{1,7});/e', 'chr("\1")', $alias);
}

但我得到:

PHP Parse error: syntax error, unexpected T_FUNCTION

关于 preg_replace_callback() 调用,可能是因为匿名函数。

无法使用版本检查来决定使用将在先前版本中导致解析错误的语言功能。解析器查看整个文件,而不考虑分支。

如果该版本的 lint 检查失败,无论分支如何,它都不会工作:

> php -l file.php
> PHP Parse error: syntax error, unexpected T_FUNCTION

就这样做吧,它应该也适用于 php 5.3 以下不支持匿名函数的版本:

function one($matches) {
    return chr(hexdec($matches[1])); 
}

function two($matches) {
    return chr($matches[1]);
}

$alias = preg_replace_callback('/&#x([0-9a-f]{1,7});/i', "one", $alias);
                                                       //^^^^ See here I
                                                       //just passed the function name
                                                       //as string
$alias = preg_replace_callback('/&#([0-9]{1,7});/', "two", $alias);

一种选择是将代码放在单独的文件中,如下所示:

if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
    include('file-5.3.0.php');
} else {
    include('file-5.x.php');
}

然后在file-5.3.0.php里面添加对应的代码:

$alias = preg_replace_callback('/&#x([0-9a-f]{1,7});/i', function($matches) { return chr(hexdec($matches[1])); }, $alias);
$alias = preg_replace_callback('/&#([0-9]{1,7});/', function($matches) { return chr($matches[1]); }, $alias);

... 并在 file-5.x.php 内添加剩余代码:

$alias = preg_replace('/&#x([0-9a-f]{1,7});/ei', 'chr(hexdec("\1"))', $alias);
$alias = preg_replace('/&#([0-9]{1,7});/e', 'chr("\1")', $alias);

解析 PHP 文件发生 任何代码 运行 之前。 if-方法永远不会跨相同的代码单元工作——即。 PHP 文件。 (不,我不会建议 "eval"。)

但是,如果有不同的 包含文件 (每个版本一个),那么 if 可以选择要包含的文件 - 但每个文件必须在解析它的PHPversion/context中仍然在句法上有效。

这实际上是一种 "sane" 方法来使用 如果使用依赖注入 或其一些变体 - 如果维护不同的组件实现真的很重要。这是因为 IoC 容器/设置将确定要包含哪些文件/实现,而服务消费者将不知道更改。

你可以使用 evalheredoc notation, but as Ilmari Karonen 指出,heredocs 充当双引号字符串,变量将被插入。这需要转义所有 $ 符号,这可能会很混乱。

或者,您可以使用 evalnowdoc notation,不幸的是,它们仅在 PHP 5.3.0 及更高版本中可用。 eval 通常被禁止,但在这种情况下,字符串不是用户指定的,因此没有安全风险。

if (version_compare(PHP_VERSION, '5.3.0') >= 0) {
    eval(<<<'CODE'
    $alias = preg_replace_callback('/&#x([0-9a-f]{1,7});/i', function($matches) { return chr(hexdec($matches[1])); }, $alias);
    $alias = preg_replace_callback('/&#([0-9]{1,7});/', function($matches) { return chr($matches[1]); }, $alias);
CODE
    );
} else {
    eval(<<<'CODE'
    $alias = preg_replace('/&#x([0-9a-f]{1,7});/ei', 'chr(hexdec("\1"))', $alias);
    $alias = preg_replace('/&#([0-9]{1,7});/e', 'chr("\1")', $alias);
CODE
    );
}

据我所知,这最接近OP的意图。此外,如果有什么好的时间和地点可以使用eval,这种情况就是那个时间和地点。

我知道这个答案为什么会出现语法错误,但另一种选择是使用与 PHP v4 和 v5 兼容的 create_function()...

$alias = preg_replace(
              '/&#x([0-9a-f]{1,7});/i', 
              create_function(
                  '$matches',
                  'return chr(hexdec($matches[1]));'
              ), 
              $alias);
$alias = preg_replace(
              '/&#([0-9]{1,7});/', 
              create_function(
                  '$matches',
                  'return chr($matches[1]);'
              ), 
              $alias);

还需要注意的是,PHP不像其他编程语言(例如C/C++)那样支持条件编译。但是,正如其他人所说,您可以使用 require()include()eval().

来绕过它