Как я могу кодировать несколько версий PHP в одном файле без ошибок?

Я пытаюсь поддерживать две версии некоторого PHP кода в одном файле с помощью version_compare, но я все равно получаю сообщение об ошибке.

код:

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(), возможно, из-за анонимных функций.

Ответ 1

Невозможно использовать проверку версий, чтобы решить использовать функцию языка, которая приведет к ошибке синтаксического анализа в предыдущей версии. Парсер просматривает весь файл, независимо от его ветвления.

Если проверка строки не выполняется для этой версии, она не будет работать, независимо от ветвления:

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

Ответ 2

Один вариант - поместить код в отдельные файлы, например:

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

Ответ 3

Анализ файлов PHP происходит до запуска любого кода. if -подход никогда не будет работать через один и тот же блок кода - то есть. PHP файл. (И нет, я не буду предлагать "eval".)

Однако, если бы был другой файл с включенным (по одному для каждой версии), то if мог выбрать, какой файл включать, но каждый из файлов должен быть синтаксически действительным в версии PHP/контексте, в котором он анализируется.

Это фактически "здравомыслящий" подход к использованию при использовании Injection Dependency или некоторых его вариаций - если действительно важно поддерживать различные реализации компонентов. Это связано с тем, что контейнер/настройка IoC определит, какие файлы (файлы)/реализации должны быть включены, а потребители услуг будут агностически изменены.

Ответ 4

Я знаю этот ответ, почему вы получаете синтаксическую ошибку, но еще один вариант - использовать create_function(), который совместим с PHP v4 и v5...

$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/С++). Однако, как заявили другие, вы можете использовать его для использования require(), include() или eval().

Ответ 5

Просто сделайте это так, и он также должен работать для версий 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);

Ответ 6

Вы можете использовать eval и heredoc нотацию, но как Ilmari Karonen указал, heredocs действуют как строки с двойными кавычками, а переменные будут интерполированы. Для этого требуется, чтобы все знаки $были экранированы, что может быть беспорядочным.

В качестве альтернативы вы можете использовать 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, эта ситуация точно такова, что время и место.