如何在同一个文件中为多个版本的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分析错误:语法错误,意外的T_FUNCTION

preg_replace_callback()调用上,可能是因为使用了匿名函数。

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

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);

并且在CCD_ 3内部添加剩余代码:

$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);

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

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

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

在运行任何代码之前都会分析PHP文件。if-方法永远不会在同一个代码单元(即PHP文件)中工作。(不,我不会建议使用"eval"。)

但是,如果包含不同的文件(每个版本一个),则if可以选择包含哪个文件,但中的每个文件在解析它的PHP版本/上下文中必须在语法上仍然有效。

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

我知道为什么你会出现语法错误,但另一个选择是使用与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()来绕过它。

您可以使用eval和heredoc表示法,但正如Ilmari Karonen所指出的,heredoc充当双引号字符串,变量将被插值。这需要所有的$标志都被转义,这可能会很混乱。

或者,您可以使用eval和nowdoc表示法,不幸的是,这只在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,那么这种情况就是那个时间和地点。

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

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);