Вы читаете строку в виде текста, и PHP замена не будет работать, если это не сделано против кода.
Вам нужна более сложная обработка (или, чтобы сказать PHP, чтобы рассмотреть этот текст так, как если бы это был код, с использованием eval
), который сильно обескуражен по соображениям безопасности и может не работать повсюду, поскольку функция eval
иногда отключается веб-мастеров, по тем же причинам безопасности).
Самый мощный вариант - использовать preg_replace_callback
для распознавания текстовых последовательностей, таких как {$varname}
, и заменить их на $varname
.Конечно $varname
должны быть определены или проверены на наличие:
function expandVariables($text, $allowedVariables) {
return preg_replace_callback('#{\$([a-z][a-z_0-9]*)}#i',
function($replace) use ($allowedVariables) {
if (array_key_exists($replace[1], $allowedVariables)) {
return $allowedVariables[$replace[1]];
}
return "NO '{$replace[1]} VARIABLE HERE.";
},
$text
);
}
$date = date('Y-m-d H:i:s');
$line = '<p>Now (at the server) is {$date}.</p>';
$vars = get_defined_vars(); // LOTS of memory :-(
// better:
// $vars = array ('date' => $date, ...); // Only allowed variables.
$eval = expandVariables($line, $vars);
print "The line is {$line}\nand becomes:\n{$eval}";
Выходы:
The line is <p>Now (at the server) is {$date}.</p>
and becomes:
<p>Now (at the server) is 2014-10-12 18:36:16.</p>
Предостережения
Эта реализация является более безопасным, чем прямо eval()
, который будет выполнять любой PHP код вообще он должен был найти в строке для чтения. Но он все еще может использоваться для вывода содержимого любой определенной переменной, если злоумышленник знает свое имя и ему разрешено запрашивать его; предположительно нереалистичным примером будет <p>Hello, {$adminPassword}!</p>
.
Чтобы быть более безопасными по-прежнему, хотя и за счет гибкости, я бы одобрить решение Виктора Свенссон, который позволяет только очень специфические переменные, которые будут установлены, и проще и быстрее:
// Remember to use 'single quotes' for '{$variables}', because you DO NOT
// want expanded them in here, but in the replaced text!
$text = str_replace(array('{$date}', '{$time}' /*, ...more... */),
array(date('Y-m-d'), date('H:i:s') /*, ...more... */),
$text);
Кроме того, вам может быть интересно проверить некоторые шаблонные решения, такие как Smarty.
Обработка весь файл
Чтобы обработать весь файл, если память не является объектом, вы можете в обоих случаях (препрега и str_) загрузить весь файл в массив строк:
$file = file($fileName);
и использовать $file
как предмет замены. Затем вы можете итерацию по результатам:
// replaceVariables receives a string and returns a string
// or receives an array of strings and returns the same.
$text = replaceVariables($file, $variables);
foreach ($text as $line) {
// Do something with $line, where variables have already been replaced.
}
Скорость
Что-то один не часто ценят то, что регулярные выражения быстро. Я не знаю, какой алгоритм сопоставления текста str_replace
использует (I думаю Boyer-Moore's), но preg имеет то преимущество, что Perlishly поддерживает массив. Он имеет более тяжелую настройку (линейную по размеру словаря), но затем она «масштабируется» лучше во время замены, а str_replace
- постоянная установка, линейно масштабируется в течение времени замены. Это означает, что preg_replace
будет экономить огромное количество раз в массовых заменах; это намного хуже в более простых контекстах.
Очень примерно, время выполнения является (S + R L V) * V (V = число переменных, L = число строк), где preg_replace имеет детектируемого S и незначительное R, в то время ул есть наоборот. При больших значениях V вы действительно хотите наименьшее R вы можете получить, даже за счет увеличения времени установки S.
Dependency on Variable N.. ? variables, 18 lines, keylen 5, vallen 20
v preg advantage
5 -82%
15 -55%
25 -2%
35 14%
45 65%
55 41%
65 51%
75 197%
85 134%
95 338%
Dependency on File length. 32 variables, ? lines, keylen 5, vallen 20
l preg advantage
5 -31%
15 -33%
25 14%
35 80%
45 116%
Конечно, ремонтопригодность также является проблемой - str_replace
делает это в одна строка, а сама функция поддерживается командой PHP. Для функции, построенной вокруг preg_replace
, требуется до 15 строк. Конечно, после тестирования вам больше не нужно его изменять, просто передайте ему словарь.
Looping
Наконец, вы можете использовать переменные со ссылкой на другие переменные. В этом случае ни PREG, ни str_ будет надежно работать, и вы должны реализовать цикл самостоятельно:
<?php
$file = "This is a {\$test}. And {\$another}. And {\$yet_another}.\n";
$vars = array(
"test" => "test",
"another" => "another {\$test}",
"yet_another" => "yet {\$another} {\$test}",
);
$text = preg_replace_callback('#{\$([a-z][a-z_0-9]*)}#i',
function($replace) use ($vars) {
if (array_key_exists($replace[1], $vars)) {
return $vars[$replace[1]];
}
return "NO '{$replace[1]} VARIABLE HERE.";
},
$file
);
$keys = array_map(function($k){ return "{\${$k}}"; }, array_keys($vars));
$vals = array_values($vars);
$text2 = str_replace($keys, $vals, $file);
$text3 = $file;
do {
$prev = $text3;
$text3 = str_replace($keys, $vals, $text3);
} while ($text3 != $prev);
print "PREG: {$text}\nSTR_: {$text2}\nLOOP: {$text3}\n";
Выход:
PREG: This is a test. And another {$test}. And yet {$another} {$test}.
STR_: This is a test. And another {$test}. And yet {$another} {$test}.
LOOP: This is a test. And another test. And yet another test test.
'{}. Это может помочь –
. Ответы ниже, как представляется, дают хорошее решение, но, не видя слишком много кода, если '{$ date}' «предполагается» заменяться в коде уже, но isn ' t, то проблема, вероятно, в том, что вы используете одиночные кавычки '' ', а не двойные кавычки' '' в строке. PHP интерпретирует '' {$ var} ''как литеральную строку в сравнении с' "{$ var}" 'как переменная. –