[英]How can I replace a variable in a string with the value in PHP?
我在數據庫中有這樣的字符串(實際的字符串包含 100 個單詞和 10 個變量):
I am a {$club} fan
我像這樣回顯這個字符串:
$club = "Barcelona";
echo $data_base[0]['body'];
我的 output 是I am a {$club} fan
。 我希望I am a Barcelona fan
。 我怎樣才能做到這一點?
使用strtr
。 它將翻譯字符串的一部分。
$club = "Barcelona";
echo strtr($data_base[0]['body'], array('{$club}' => $club));
對於多個值(演示):
$data_base[0]['body'] = 'I am a {$club} fan.'; // Tests
$vars = array(
'{$club}' => 'Barcelona',
'{$tag}' => 'sometext',
'{$anothertag}' => 'someothertext'
);
echo strtr($data_base[0]['body'], $vars);
程序輸出:
I am a Barcelona fan.
/**
* A function to fill the template with variables, returns filled template.
*
* @param string $template A template with variables placeholders {$variable}.
* @param array $variables A key => value store of variable names and values.
*
* @return string
*/
public function replaceVariablesInTemplate($template, array $variables){
return preg_replace_callback('#{(.*?)}#',
function($match) use ($variables){
$match[1] = trim($match[1], '$');
return $variables[$match[1]];
},
' ' . $template . ' ');
}
我建議使用sprintf()函數。
與其存儲I am a {$club} fan
,不如使用I am a %s fan
,因此您的echo命令將如下所示:
$club = "Barcelona";
echo sprintf($data_base[0]['body'],$club);
輸出:我是巴塞羅那球迷
這將使您可以自由地將相同的代碼與任何其他變量一起使用(您甚至不必記住變量名)。
因此,此代碼對於相同的字符串也有效:
$food = "French fries";
echo sprintf($data_base[0]['body'], $food);
輸出:我是炸薯條迷
$language = "PHP";
echo sprintf($data_base[0]['body'], $language);
輸出:我是 PHP 愛好者
編輯:這個答案仍然得到了贊成,所以人們需要注意下面的代碼片段中存在的幼稚插值技術存在安全漏洞。 攻擊者可以在輸入字符串中包含任意變量,這將揭示有關服務器的信息或運行時變量寄存器中的其他數據。 這是由於通用表達式搜索的執行方式,它找到任意變量名稱模式,然后在隨后的compact
調用中逐字使用這些變量名稱。 這會導致客戶端控制類似於eval
的服務器端行為。 我將這個答案留給后代。
您正在尋找嵌套字符串插值。 可以在博客文章中閱讀一個理論:用於動態執行雙引號字符串變量插值的 PHP 核心函數。
主要問題是您並不真正了解所有可用的變量,或者可能有太多無法列出。
考慮以下經過測試的代碼片段。 我從 Mohammad Mohsenipur 那里偷了正則表達式。
$testA = '123';
$testB = '456';
$testC = '789';
$t = '{$testA} adsf {$testB}adf 32{$testC} fddd{$testA}';
echo 'before: ' . $t . "\n";
preg_match_all('~\{\$(.*?)\}~si', $t, $matches);
if ( isset($matches[1])) {
$r = compact($matches[1]);
foreach ( $r as $var => $value ) {
$t = str_replace('{$' . $var . '}', $value, $t);
}
}
echo 'after: ' . $t . "\n";
您的代碼可能是:
$club = 'Barcelona';
$tmp = $data_base[0]['body'];
preg_match_all('~\{\$(.*?)\}~si', $tmp, $matches);
if ( isset($matches[1])) {
$r = compact($matches[1]);
foreach ( $r as $var => $value ) {
$tmp = str_replace('{$' . $var . '}', $value, $tmp);
}
}
echo $tmp;
if (preg_match_all('#\$([a-zA-Z0-9]+)#', $q, $matches, PREG_SET_ORDER));
{
foreach ($matches as $m)
{
eval('$q = str_replace(\'' . $m[0] . '\', $' . $m[1] . ', $q);');
}
}
這匹配所有 $variables 並用值替換它們。
我沒有包含 {},但添加它們應該不會太難,像這樣......
if (preg_match_all('#\{\$([a-zA-Z0-9]+)\}#', $q, $matches, PREG_SET_ORDER));
{
foreach ($matches as $m)
{
eval('$q = str_replace(\'' . $m[0] . '\', $' . $m[1] . ', $q);');
}
}
雖然它似乎比硬編碼每個變量要慢一些。 它引入了 eval 的安全漏洞。 這就是為什么我的正則表達式如此有限的原因。 限制 eval 可以抓取的范圍。
我用 Ajax 編寫了自己的正則表達式測試器,所以我可以在輸入時看到我的表達式是否可以工作。 我有我喜歡在我的表達式中使用的變量,因此我不需要為每個表達式重新鍵入相同的位。
我發現這些方法有時很有用:
$name = 'Groot';
$string = 'I am {$name}';
echo eval('return "' . $string . '";');
$data = array('name' => 'Groot');
$string = 'I am {$data[name]}';
echo eval('return "' . $string . '";');
$name = 'Groot';
$data = (object)get_defined_vars();
$string = 'I am {$data->name}';
echo eval('return "' . $string . '";');
這是我的解決方案:
$club = "Barcelona";
$string = 'I am a {$club} fan';
preg_match_all("/\{\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/", $string, $matches);
foreach ($matches[0] as $key => $var_name) {
if (!isset($GLOBALS[$matches[1][$key]]))
$GLOBALS[$matches[1][$key]] = 'default value';
$string = str_replace($var_name, $GLOBALS[$matches[1][$key]], $string);
}
您可以使用簡單的解析器將 {$key} 替換為映射中的值(如果存在)。
像這樣使用它:
$text = templateWith('hello $item}', array('item' => 'world'...));`
我的第一個版本是:
/**
* Template with a string and simple map.
* @param string $template
* @param array $substitutions map of substitutions.
* @return string with substitutions applied.
*/
function templateWith(string $template, array $substitutions) {
$state = 0; // forwarding
$charIn = preg_split('//u', $template, -1, PREG_SPLIT_NO_EMPTY);
$charOut = array();
$count = count($charIn);
$key = array();
$i = 0;
while ($i < $count) {
$char = $charIn[$i];
switch ($char) {
case '{':
if ($state === 0) {
$state = 1;
}
break;
case '}':
if ($state === 2) {
$ks = join('', $key);
if (array_key_exists($ks, $substitutions)) {
$charOut[] = $substitutions[$ks];
}
$key = array();
$state = 0;
}
break;
case '$': if ($state === 1) {
$state = 2;
}
break;
case '\\': if ($state === 0) {
$i++;
$charOut[] = $charIn[$i];
}
continue;
default:
switch ($state) {
default:
case 0: $charOut[] = $char;
break;
case 2: $key[] = $char;
break;
}
}
$i++;
}
return join('', $charOut);
}
也許以下代碼段(部分)對某人有用。
/**
* Access an object property using "dot" notation
*
* @param object $object
* @param string|null $path
* @param mixed $default
* @return mixed
*/
function xobject_get(object $object, $path, $default = null) {
return array_reduce(explode('.', $path), function ($o, $p) use ($default) {
return is_numeric($p) ? $o[$p] ?? $default : $o->$p ?? $default;
}, $object);
}
/**
* Access an array's property using "dot" notation
*
* @param array $array
* @param string|null $path
* @param mixed $default
* @return mixed
*/
function xarray_get(array $array, $path, $default = null) {
return array_reduce(explode('.', $path), function ($a, $p) use ($default) {
return $a[$p] ?? $default;
}, $array);
}
/**
* Replaces placeholders from a string with object or array values using "dot" notation
*
* Example:
* "The book {title} was written by {author.name}" becomes "The book Harry Potter was written by J.K. Rowling"
*
* @param array|object $data
* @param string $template
* @return string
*/
function render_template($data, string $template) {
preg_match_all("/\{([^\}]*)\}/", $template, $matches);
$replace = [];
foreach ($matches[1] as $param) {
$replace['{'.$param.'}'] = is_object($data) ? xobject_get($data, $param) : xarray_get($data, $param);
}
return strtr($template, $replace);
}
您可以使用preg_replace_callback獲取變量名稱,例如:
$data_base[0]['body'] = preg_replace_callback(
'#{(.*?)}#',
function($m) {
$m[1] = trim($m[1], '$');
return $this->$m[1];
},
' ' . $data_base[0]['body'] . ' '
);
注意:我寫的這段代碼是針對class($this);
. 您可以在類中聲明一個變量。 然后使用此代碼檢測變量並將它們替換為:
<?php
class a {
function __construct($array) {
foreach($array as $key => $val) {
$this->$key = $val;
}
}
function replace($str){
return preg_replace_callback(
'#{(.*?)}#', function($m) {$m[1] = trim($m[1], '$'); return $this->$m[1];},
' ' . $str . ' ');
}
}
$obj = new a(array('club' => 3523));
echo $obj->replace('I am a {$club} fan');
輸出:
I am a 3523 fan
試試preg_replace PHP 函數。
<?php
$club = "Barcelona";
echo $string = preg_replace('#\{.*?\}#si', $club, 'I am a {$club} fan');
?>
對於你的情況,老實說,我看不出有理由不使用 eval :)
如果變量太進入數據庫,這里有一些額外的方法來定義變量:
$my_variable_name = 'club'; //coming from database
$my_value = 'Barcelona'; //coming from database
$my_msg= 'I am a {$club} fan'; //coming from database
$$my_variable_name = $my_value; // creating variable $club dinamically
$my_msg = eval("return \"$my_msg\";"); // eating the forbidden fruit
echo $my_msg; // prints 'I am Barcelona fan'
這段代碼已經過全面測試,可與 php 7 一起使用。但如果您允許您的用戶將此類字符串定義到您的數據庫中,最好不要這樣做。 您應該只使用受信任的數據運行 eval。
這樣的事情應該可以解決您的問題:
$club = "Barcelona";
$var = 'I am a {$club} fan';
$res = preg_replace('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/e', "$$1", $var);
echo "$res\n";
這是一個單行preg_replace
。
在 PHP 5.5 中,不推薦使用/e
修飾符。 您可以改用回調:
$club = "Barcelona";
$var = 'I am a {$club} fan';
$res = preg_replace_callback('/\{\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\}/',
create_function(
'$matches',
'extract($GLOBALS, EXTR_REFS | EXTR_SKIP); return $$matches[1];'),
$var);
echo "$res\n";
請注意,這使用了導入所有全局變量的技巧。 這可能不是您想要的。 可能使用閉包會是一個更好的主意。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.