PHP 7.1 用动态变量替换多个值

PHP 7.1 replace multiple values with dynamic variables

我是 PHP 的新手,虽然我找到了解决问题的方法,但我觉得肯定有更简单的方法来实现相同的结果:

这是我需要做的:

我有一个这样的字符串(在真实的字符串中有大约 25 个值要替换)

"We have received ##AMOUNT## ##CURRENCY## for your OrderID n. ##ORDER_ID##"

在这个字符串中我必须替换
##AMOUNT## 具有名为 $AMOUNT
的变量的值 ##CURRENCY## 变量值为 $CURRENCY
##ORDER_ID## 变量值 $ORDER_ID

目前我创建了一个数组:

$flds=['AMOUNT','CURRENCY','ORDER_ID'];

我使用循环和动态变量替换:
但我看到 str_replace 也接受数组,因此可以构建一个更优雅(和高效)的解决方案 但是...我找不到它

可以给点提示吗?

谢谢

更优雅的方式是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

您可以对两个数组使用 str_replace 函数,一个是搜索词,另一个是替换词:

 $words = ["##AMOUNT##", "##CURRENCY##", "##ORDER_ID##"];
 $replaces = [$AMOUNT,$CURRENCY,$ORDER_ID];
 $newString = str_replace($words, $replaces, $string);
 echo $newString;

您可以使用str_replace(), if you got arbitrary variables you can use 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

结果:

我们已收到您的 OrderID n 的 123 英镑。 20123

如果您正在寻找一种方法来定义 variables/placeholders 一次,然后进行匹配和替换,您可以这样做:

<?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

我会制作一个简单的模板 class 来解析它,

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"

可以看到here live:

而且您可以随时对其进行扩展并添加功能,例如从作业中删除 ##,以及删除任何未使用的标签。等...

基本上它只是一个变量的数组管理工具。因为我们正在构建一个这样的数组:

[
  '##AMOUNT##' => 'foo',
  '##CURRENCY##' => 'bar',
  '##ORDER_ID##' => 'hello'
];

然后使用 str_replace 我们使用键作为搜索,值作为替换值。

如果您想从标签分配中删除 ##,只需更改此:

public function assign($key, $value)
{
    $this->vars['##'.$key.'##'] = $value;
}

然后这样调用:

$T->assign('AMOUNT', 'foo');

这里的真正好处是有一个 class 来实现您的逻辑。它保持清洁和可重复使用。

更新

正如@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.
    } 

你可以看到这个例子here

数组 /\s{2,}/ 中的第二个 只是在 space 上取 运行 并将它们压缩为单个 space,所以如果你有 4 spaces 它变成了一个 space。它没有很好的记录,但 preg_replace 可以像 str_replace 一样接受数组。

这就是为什么我建议构建一个 class,它为您提供了一个很好的地方来实现所有这些“东西”(如果您愿意),而不必一直重写它。

str_replace 将使用数组。如果 $find 是一个数组并且 $replace 是一个字符串,它将用 $replace 中的字符串替换 $find 中的所有内容,如果两者都是数组,它将替换每个对应的元素 $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".

之前用 replace 替换 "find" 单词和 find2 的一部分 "find"

如果你想避免这种情况,你可以使用 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