PHP 7.1 замена нескольких значений динамическими переменными
Я довольно новичок в PHP, и хотя я нашел способ решить свою проблему, я чувствую, что, безусловно, есть гораздо более простой способ достичь того же результата:
Вот что мне нужно сделать:
У меня есть такая строка (в реальной есть около 25 значений, которые нужно заменить)
"We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"
В этой строке я должен заменить##AMOUNT## со значением переменной named $AMOUNT##CURRENCY## со значением переменной $CURRENCY##ORDER_ID## со значением переменной $ORDER_ID
В настоящее время я создал массив:
$flds=['AMOUNT','CURRENCY','ORDER_ID'];
И я заменяю с помощью цикла и динамических переменных:
но я видел, что str_replace принимает также массивы и поэтому может построить более элегантное (и эффективное) решение
но...Я не могу найти его
Можете дать несколько подсказок?
Спасибо
6 ответов:
Вы можете использовать str_replace(), Если у вас есть произвольные переменные, вы можете использовать compact(), чтобы поместить их в массив.
<?php $str = "We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"; $AMOUNT = 123; $CURRENCY = 'GBP'; $ORDER_ID = 20123; $find = ['##AMOUNT##','##CURRENCY##','##ORDER_ID##']; $replace = compact('AMOUNT', 'CURRENCY', 'ORDER_ID'); echo str_replace($find, $replace, $str);Результат:
Мы получили 123 фунта стерлингов за ваш ордер n. 20123
Если вы ищете способ просто определить ваши переменные/заполнители один раз, а затем сопоставить и заменить, Вы можете сделать это следующим образом:
<?php $str = "We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"; $AMOUNT = 123; $CURRENCY = 'GBP'; $ORDER_ID = 20123; $find = ['AMOUNT', 'CURRENCY', 'ORDER_ID']; echo str_replace( array_map(function($v){ return '##'.$v.'##'; }, $find), compact(...$find), $str );
Можно использовать функцию str_replace с двумя массивами, одним из искомых слов и вторым из замен:
$words = ["##AMOUNT##", "##CURRENCY##", "##ORDER_ID##"]; $replaces = [$AMOUNT,$CURRENCY,$ORDER_ID]; $newString = str_replace($words, $replaces, $string); echo $newString;
Я бы сделал простой шаблон класса для его разбора,
class SimpleTemplate { protected $src; protected $vars; public function __construct($src) { $this->src = $src; } public function assign($key, $value) { $this->vars[$key] = $value; } public function out() { return str_replace(array_keys($this->vars),$this->vars,$this->src); } } $T = new SimpleTemplate("We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"); $T->assign('##AMOUNT##', 'foo'); $T->assign('##CURRENCY##', 'bar'); $T->assign('##ORDER_ID##', 'hello'); echo $T->out();Выходы:
"We have received foo bar for your OrderID n. hello"Вы можете увидеть его здесь живут :
И вы всегда можете расширить его и добавить функции, такие как удаление
##из назначения и удаление любых неиспользуемых тегов. и т.д...В основном это просто инструмент управления массивами для ваших переменных. Потому что мы строим массив вот так:
[ '##AMOUNT##' => 'foo', '##CURRENCY##' => 'bar', '##ORDER_ID##' => 'hello' ];И затем, используя
str_replace, мы используем ключи как поиск, значение как восстановительная стоимость.Если вы хотите удалить
##из назначения тега, просто измените это:public function assign($key, $value) { $this->vars['##'.$key.'##'] = $value; }А затем позвоните так:
$T->assign('AMOUNT', 'foo');Реальная выгода здесь-это наличие класса для реализации вашей логики. Он сохраняет его чистым и многоразовым.
Обновление
Как упоминалось в комментариях @LawrenceCherone, вы можете получить более чистый интерфейс, используя пару магических методов.class SimpleTemplate { protected $src; protected $vars; public function __construct($src) { $this->src = $src; } public function __set($key, $value) { $this->vars['##'.strtoupper($key).'##'] = $value; } public function __toString() { return str_replace(array_keys($this->vars),$this->vars,$this->src); } } $T = new SimpleTemplate("We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"); $T->Amount = 'foo'; //any casing works because of the transforms, in __set $T->CURRENCY = 'bar'; $T->order_id = 'hello'; echo $T; //using __toString() lets us just output the class as our result string.Конкретно
__setи__toString. Для этого я сделал немного преобразований наkey, чтобы сделать его немного менее подверженным ошибкам и немного менее уродливым. Например, использование смешанной оболочки для динамических свойств. С помощьюstrtoupperони могут быть введены в любом случае, и удаление#предотвращает необходимость обернуть их так$T->{'##AMOUNT##'} = 'foo';Последнее, что я добавлю, это то, что если вы можете иметь "теги", которые не назначены, но хотите их удалить, вы можете использовать этот regx для их удаления.
public function __toString() { $str = str_replace(array_keys($this->vars),$this->vars,$this->src); return preg_replace(['/##\w+##/', '/\s{2,}/'], ['', ' '], $str); //remove any left over ##{word}## tags, and compress any run-on spaces. }Вы можете увидеть пример этого здесь
Второй в массиве
Вот почему я предлагаю создать класс, это дает вам хорошее место для реализации всего этого "материала", Если вы хотите, и не нужно постоянно переписывать его./\s{2,}/,just takes run on spaces and compresses them to a single space, so if you have like 4 spaces it becomes a single space. It's not well documented butpreg_replaceможно взять массив точно так же, как это делаетstr_replace.
str_replaceбудет работать с массивами. Если$findявляется массивом и$replaceявляется строкой, то он заменит все в$findстрокой в$replaceесли оба массива являются массивами, то он заменит каждый соответствующий элемент$find[index]их соответствующим$replace[index]примером:Однако есть небольшая загвоздка в том, что замены выполняются последовательно. Как правило, это не проблема, пока вы не столкнетесь с чем-то вроде:$find = ["find1", "find2" ]; $replace = [ "replace1", "replace2" ]; $string = "Find find1 and find2"; echo str_replace($find, $replace, $string); // "Find replace1 and replace2"$find = [ "find", "find2" ]; $replace = [ "replace", "replaceXX2" ]; $string = "Find find1 and find2"; echo str_replace($find, $replace, $string); // "Find replace1 and replace2"Почему? Потому что он заменит как слово" найти", так и слово " найти" это часть find2 с заменой, прежде чем он даже ищет "find2".
Если вы хотите избежать этого, вы можете использовать
strtrследующим образом:$find = [ "find" => "replace" , "find2" => "replaceXX" ]; $string = "Find find1 and find2"; echo strtr($string, $find); // "Find replace1 and replaceXX"
Другой способ с ответом @Lawrence Cherone. Может быть, вы хотите использовать
key => valueСписок.<?php $message = "We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"; $messageParameters = [ 'AMOUNT' => 83, 'CURRENCY' => 'USD', 'ORDER_ID' => 3271096 ]; $parsedMessage = str_replace( array_map(function($v){ return '##'.$v.'##'; }, array_keys($messageParameters)), array_values($messageParameters), $message ); echo $parsedMessage;Результат:
We have received 83 USD for your OrderID n. 3271096
Более элегантный способ-это
printfфунция.vsprintf("We have received %s %s for your OrderID n. %s", array($AMOUNT, $CURRENCY, $ORDER_ID));Подробнее здесь: http://php.net/manual/en/function.vsprintf.php
Comments