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 принимает также массивы и поэтому может построить более элегантное (и эффективное) решение но...Я не могу найти его

Можете дать несколько подсказок?

Спасибо

237   6  

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

Https://3v4l.org/1E2Mm

Результат:

Мы получили 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
);

Https://3v4l.org/ekHYB

Можно использовать функцию 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 but preg_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

Https://3v4l.org/9b7lO

Более элегантный способ-это 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

    Ничего не найдено.

Добавить ответ:
Отменить.