【问题标题】:Does PHP have a feature like Python's template strings?PHP 有没有像 Python 的模板字符串这样的特性?
【发布时间】:2011-12-02 17:53:06
【问题描述】:

Python 有一个名为template strings 的功能。

>>> from string import Template
>>> s = Template('$who likes $what')
>>> s.substitute(who='tim', what='kung pao')
'tim likes kung pao'

我知道 PHP 允许你写:

"Hello $person"

并替换了$person,但模板可以在代码的各个部分重复使用?

【问题讨论】:

标签: php string templates template-variables


【解决方案1】:

你也可以使用strtr:

$template = '$who likes $what';

$vars = array(
  '$who' => 'tim',
  '$what' => 'kung pao',
);

echo strtr($template, $vars);

输出:

tim likes kung pao

【讨论】:

  • 这种方法的一个缺点是没有 IDE 可以帮助您验证模板及其参数,您基本上只能靠自己。
【解决方案2】:

你可以像这样使用模板字符串:

$name = "Maria";
$info["last_name"] = "Warner";

echo "Hello {$name} {$info["last_name"]}";

这将回显Hello Maria Warner

【讨论】:

  • 这种模板字符串方式类似于Javascript中的模板字符串方式。
  • 这个应该是正确的答案。只有一件事,为什么它不适用于单个顶点?
  • @EuberDeveloper 不确定,但例如与 " $var="A" 和 echo " $var " 有效而 ' $var ' 无效?(注意单引号)
  • @Miguel 我在 repl.it 上试过,正是上面评论答案的代码。如果你用 ' 替换 ",它会停止工作。但是,阅读 php 文档,这似乎是正常的行为
  • @EuberDeveloper 对,和这个stackoverflow.com/questions/3446216/…有关
【解决方案3】:

我认为有很多方法可以做到这一点......但我想到了这一点。

$search = array('%who%', '%what_id%');
$replace = array('tim', 'kung pao');
$conference_target = str_replace(
    $search,
    $replace,
    "%who% likes %what%"
);

哈,我们的框架中甚至有一个使用vsprintf

class Helper_StringFormat {

    public static function sprintf($format, array $args = array()) {

        $arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);

        for ($pos = 0; preg_match('/(?<=%)\(([a-zA-Z_]\w*)\)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
            $arg_pos = $match[0][2];
            $arg_len = strlen($match[0][0]);
            $arg_key = $match[1][0];

            if (! array_key_exists($arg_key, $arg_nums)) {
                user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
                return false;
            }
            $format = substr_replace($format, $replace = $arg_nums[$arg_key] . '$', $arg_pos, $arg_len);
            $pos = $arg_pos + strlen($replace);
        }

        return vsprintf($format, array_values($args));
    }
}

貌似来自the sprintf page

这允许像这样的调用:

sprintfn('second: %(second)s ; first: %(first)s', array(
    'first' => '1st',
    'second'=> '2nd'
));

更新
这是一个更新,可以做你想做的事......虽然没有完全测试

class Helper_StringFormat {

    public static function sprintf($format, array $args = array()) {
        $arg_nums = array_slice(array_flip(array_keys(array(0 => 0) + $args)), 1);

        for ($pos = 0; preg_match('/(?<=%)\(([a-zA-Z_][\w\s]*)\)/', $format, $match, PREG_OFFSET_CAPTURE, $pos);) {
            $arg_pos = $match[0][1];
            $arg_len = strlen($match[0][0]);
            $arg_key = $match[1][0];

            if (! array_key_exists($arg_key, $arg_nums)) {
                user_error("sprintfn(): Missing argument '${arg_key}'", E_USER_WARNING);
                return false;
            }
            $format = substr_replace($format, $replace = $arg_nums[$arg_key] . '$', $arg_pos, $arg_len);
            $pos = $arg_pos + strlen($replace); // skip to end of replacement for next iteration
        }

        return vsprintf($format, array_values($args));
    }
}

$str = "%(my var)s now work with a slight %(my var2)s";
$repl = array("my var" => "Spaces", "my var2" => "modification.");

echo Helper_StringFormat::sprintf($str, $repl);

输出
空间现在只需稍作修改即可工作。

【讨论】:

  • 这很好,除了没有办法逃避%(some character) 序列。如果我能解决这个问题,我会在这个线程中发布代码
  • 顺便说一句,您的第二个链接名称中有错字。 (sprtinf)
【解决方案4】:

另一种更简单的方法是:

$s = function ($vars) {
    extract($vars);
    return "$who likes $what";
};
echo $s(['who' => 'Tim', 'what' => 'King Pao']); // Tim likes King Pao

是的,PHPStorm 会抱怨...

【讨论】:

    【解决方案5】:

    我做了一个函数来做你想做的事。我把它写成“又快又脏”,因为我没有太多时间重构它,也许我把它上传到我的 github。

    编辑:错误更正...

    像这样使用它

        formattemplatter(
                         '$who likes $what'
                         , array(
                                   'who'  => 'Tim'
                                 , 'what' => 'Kung Pao'
                         )
        );
    

    变量只能是 [a-zA-Z0-9_]。

     function formattemplater($string, $params) {
        // Determine largest string
        $largest = 0;
        foreach(array_keys($params) as $k) {
            if(($l=strlen($k)) > $largest) $largest=$l;
        }
    
        $buff   = '';
    
        $cp     = false;    // Conditional parenthesis
        $ip     = false;    // Inside parameter
        $isp    = false;    // Is set parameter
    
        $bl     = 1;    // buffer length
        $param  = '';   // current parameter
    
        $out    = '';  // output string
        $string .= '!';
    
        for($sc=0,$c=$oc='';isset($string{$sc});++$sc,++$bl) {
            $c = $string{$sc};
    
            if($ip) {
                $a = ord($c);
    
                if(!($a == 95 || (                  // underscore
                        ($a >= 48 && $a <= 57)      // 0-9
                        || ($a >= 65 && $a <= 90)   // A-Z
                        || ($a >= 97 && $a <= 122)  // a-z
                    )
                )) {
    
                    $isp = isset($params[$buff]);
    
                    if(!$cp && !$isp) {
                        trigger_error(
                                sprintf(
                                        __FUNCTION__.': the parameter "%s" is not defined'
                                        , $buff
                                )
                                , E_USER_ERROR
                        );
                    } elseif(!$cp || $isp) {
                        $out    .= $params[$buff];
                    }
    
                    $isp    = $isp && !empty($params[$buff]);
                    $oc     = $buff = '';
                    $bl     = 0;
                    $ip     = false;
                }
            }
    
            if($cp && $c === ')') {
                $out .= $buff;
    
                $cp = $isp = false;
                $c  = $buff = '';
                $bl = 0;
            }
    
            if(($cp && $isp) || $ip)
                $buff .= $c;
    
            if($c === '$' && $oc !== '\\') {
                if($oc === '(')  $cp = true;
                else $out .= $oc;
    
                $ip   = true;
                $buff = $c = $oc = '';
                $bl   = 0;
            }
    
            if(!$cp && $bl > $largest) {
                $buff   = substr($buff, - $largest);
                $bl     = $largest;
            }
    
            if(!$ip && ( !$cp || ($cp && $isp))) {
                $out .= $oc;
                if(!$cp) $oc = $c;
            }
        }
    
        return $out;
    }
    

    【讨论】:

      【解决方案6】:

      我个人最喜欢sprintf(或vsprintf,用于参数数组)。它将它们按预期顺序放置,根据需要强制类型,并提供更多高级功能。

      例子:

      $var = sprintf("%s costs %.2f dollars", "Cookies", 1.1);
      

      这将产生值Cookies cost 1.10 dollars

      针对不同的用例有一整套 printf 函数,都列在“另见”下。

      非常通用:提供变量、数组组件、函数结果等的相同方法。

      【讨论】:

      • 有一个附加函数/类来模拟 sprintf 的答案——它自 PHP 4 以来就内置了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-25
      • 2012-08-16
      • 1970-01-01
      • 2015-08-13
      • 2017-03-09
      • 1970-01-01
      相关资源
      最近更新 更多