PHP — Использование обратных ссылок с file_exists в preg_replace

Я пытаюсь заменить содержимое некоторых тегов во включенных файлах содержимым из других файлов:

$view = preg_replace('/{include ([[:alnum:]\.-]+)}/', ((file_exists('template/$1.html')) ? 'OK $1' : 'KO $1'), file_get_contents('myTemplateFile.tpl'));

Все ссылки {include file.ext}, которые я получил в myTemplateFile.tpl, заменены на KO file.ext вместо OK file.ext.

Однако, если я жестко запрограммирую file_exists('template/file.ext'), то будет отображаться правильная строка.

Мне кажется, что обратная ссылка не правильно разрешена внутри вызова file_exists.

Что я делаю неправильно?


person Bernard Rosset    schedule 14.02.2014    source источник


Ответы (2)


preg_replace('/{include ([[:alnum:]\.-]+)}/', ((file_exists('template/$1.html')) ? 'OK $1' : 'KO $1'), file_get_contents('myTemplateFile.tpl'))

Сначала выполняется file_exists('template/$1.html'), затем передается OK $1 или KO $1 (скорее всего, последнее) в preg_replace, который затем заменяет все вхождения.

Вам нужно будет использовать обратный вызов, чтобы сделать эту работу, а не вызывать file_exists в качестве аргумента:

preg_replace_callback(
    '/{include ([[:alnum:]\.-]+)}/',
    function (array $m) {
        return file_exists("template/$m[1].html") ? "OK $m[1]" : "KO $m[1]";
    },
    file_get_contents('myTemplateFile.tpl')
)
person deceze♦    schedule 14.02.2014
comment
Спасибо! Я не обращал внимания на то, как разрешались рекурсивные вызовы... Конечно, сначала вызывается file_exists, прежде чем preg_replace даже оценивается! - person Bernard Rosset; 14.02.2014

$view = preg_replace(
    '/{include ([[:alnum:]\.-]+)}/', 
    ((file_exists('template/$1.html')) ? 'OK $1' : 'KO $1'), 
    file_get_contents('myTemplateFile.tpl')
);

Приведенный выше код выполняется следующим образом:

$contents = file_get_contents('myTemplateFile.tpl');

if ((file_exists('template/$1.html')) {
    $result = preg_replace('/{include ([[:alnum:]\.-]+)}/', 'OK $1', $contents);
} else {
    $result = preg_replace('/{include ([[:alnum:]\.-]+)}/', 'KO $1', $contents);
}

Как видите, вызов file_exists() выполняется перед оператором preg_replace(). Он проверяет наличие файла "template/$1.html", где $1 – это литеральная строка, не имеющая специального значения. Этот файл не существует, и блок else (первоначально 'KO $1') всегда будет выполняться.

Короче говоря, вы не можете использовать обратные ссылки из функции preg_replace() вне функции preg_replace(). Решение preg_replace_callback():

preg_replace_callback(
    '/{include ([[:alnum:]\.-]+)}/',
    function ($m) {
        return file_exists('template/'.$m[1].'html') ? 'OK '.$m[1]: 'KO '.$m[1];
    },
    file_get_contents('myTemplateFile.tpl')
);

Смотрите также:

person Amal Murali    schedule 14.02.2014
comment
Спасибо за помощь, хоть ты и второй... +1 все равно дал в награду ;о) - person Bernard Rosset; 14.02.2014
comment
Ну мой плохой. Однако другой ответ шаг за шагом объясняет, откуда возникает проблема, помогая мне вспомнить, как обрабатываются рекурсивные вещи. :oP Надеюсь, у тебя не будет обид на меня из-за того, что я до сих пор второй... ;о) - person Bernard Rosset; 15.02.2014