PHP - 如何将命名变量放在字符串中使用在变量之前定义的字符串

时间:2014-04-16 00:17:24

标签: php

我正在寻找等同于pythons % operator的PHP。

# PYTHON Example
foo = 'variable_string'
baz = 'characters'

new_string = 'my %(foo)s of %(baz)s' % locals()

My Vague php context:

注意:这是为了说明我为什么要这样做,它没有反映任何代码。

// PHP Example context
class Controller {
    ...
    // Singles quotes used in intentionally
    // This template string is meant to be overloadable.
    public $template = '<h1>{$title}</h1><h2>{$subheading}</h2>'; 
    ....
}

class View {
    ...
    public function render($template) {
        $title = 'variable string';
        $subheading = 'some other variable stuff';
        // Example of the python operator
        return magically_put_variables_in_string(
            $template, 
            magically_get_named_variables_from_scope()
        );
    }
    ...
}
  • 具体来说,我想要最规范的magically_put_variables_in_string实施。
  • 我不能假设我可以使用晚于php 5.3
  • 的任何内容
  • 我不介意传递明确的array('$variable_name' => $variable_name)
  • 无需定义新功能即可完成此操作。

最后注意:我已经为我的特定用例构建了一个解决方案,但它不能满足这个问题。

11 个答案:

答案 0 :(得分:11)

一个好的方法是strtr

strtr('<h1>{foo}</h1><h2>{bar}</h2>', array(
  '{foo}' => $foo,
  '{bar}' => $bar,
));

您也可以使用get_defined_vars()来获取当前作用域中可访问的变量数组,但我个人更喜欢显式枚举。


使用strtr优于str_replace的一个微妙优势是strtr搜索字符串的已替换部分以进行进一步替换。 str_replace州的手册页:

  

由于str_replace()从左到右替换,因此在执行多次替换时,它可能会替换以前插入的值。

答案 1 :(得分:3)

听起来你正在尝试进行类型转换。您可以使用print_fsprint_f两个函数执行此操作。第一个将回显输出,第二个将返回一个字符串。您可以将命名变量传递给函数,如:

// PHP Example context
class Controller {
    ...
    // Singles quotes used in intentionally
    // This template string is meant to be overloadable.
    public $template = '<h1>%s</h1><h2>%s</h2>'; // Update this line
    ....
}

class View {
    ...
    public function render($template) {
        $title = 'variable string';
        $subheading = 'some other variable stuff';

        return sprint_f($template, $title, $subheading);
    }
    ...
}

<强>更新

您还可以通过向类型添加数字说明符来在类型转换中定位变量。假设您出于某种原因想要两次标题:

public $template = '<h1>%1$s</h1><h2>%2$s</h2><h3>%1$s</h3>';

这将在sprint_f()<h1>的{​​{1}}函数中进行类型转换交换第一个变量(第二个参数)。您放在说明符中的数字应该与参数位置匹配,因此<h3>将是%1$s之后的第一个参数,依此类推。您可以拥有任意类型的任意数量的类型转换说明符。它们如下:

  • - 字面百分比字符。不需要参数。
  • b - 将参数视为整数,并以二进制数表示。
  • c - 该参数被视为一个整数,并显示为具有该ASCII值的字符。
  • d - 将参数视为整数,并以(带符号)十进制数表示。
  • e - 该论点被视为科学记数法(例如1.2e + 2)。精度说明符代表自PHP 5.2.1以来小数点后的位数。在早期版本中,它被视为有效数字的位数(少一个)。
  • E - 与%e类似,但使用大写字母(例如1.2E + 2)。
  • f - 将参数视为浮点数,并显示为浮点数(可识别区域设置)。
  • F - 将参数视为浮点数,并显示为浮点数(非区域设置)。自PHP 4.3.10和PHP 5.0.3起可用。
  • g - 较短的%e和%f。
  • G - 较短的%E和%f。
  • o - 将参数视为整数,并以八进制数表示。
  • s - 将参数视为字符串并显示为字符串。
  • u - 将参数视为整数,并以无符号十进制数表示。
  • x - 该参数被视为一个整数,并以十六进制数字表示(使用小写字母)。
  • X - 该参数被视为一个整数,并以十六进制数字表示(使用大写字母)。

答案 2 :(得分:1)

我希望str_replace正是您所寻找的。

Description ¶

mixed str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
This function returns a string or an array with all occurrences of search in subject replaced with the given replace value.

您可以将标记数组作为主题,并将相应的标记值作为替换数组。

<?php

# PHP Example
$foo = 'variable_string'
$baz = 'characters'

$new_string = str_replace(array("%foo%","%baz%"),array($foo,$baz), "my %foo% of %baz%s");

?>


<?php
// Provides: <body text='black'>
$bodytag = str_replace("%body%", "black", "<body text='%body%'>");
?>

答案 3 :(得分:0)

您可以使用sprintf

$template = '<h1>%s</h1>'; 
echo sprintf($template, 'Hello world');

答案 4 :(得分:0)

我能想到的最佳方式:

public function render($template) {
     $data = array(
                 '{$title}' => 'variable string', 
                 '{$subheading}' => 'other variable string'
                 );

     return str_replace(array_keys($data), array_values($data), $template);
}  

答案 5 :(得分:0)

如果您完全信任该模板,则可能会给eval()一个机会:

class View
{

    public function render(array $model, $template)
    {
         extract($model);
         return eval(sprintf('return "%s";', addslashes($template)));
    }

}

$template = 'Hello "${object}"';
$model = array("object" => "world");

$view = new View();
$rendered = $view->render($model, $template);

echo $rendered, "\n";

答案 6 :(得分:0)

我一直喜欢的PHP是它将字符串的基础逻辑保留为字符数组。在php中,你可以像在C ...中那样做。

下面的代码将使用替换数组中定义的任何内容替换所有转义名称(如果未定义任何内容,则替换为空)。

$replacements['color1'] = 'red';
$replacements['color2'] = 'green';

$template = "Apples are {color1} , grapes are {color2}\n";

// this will oputput 'Apples are red , grapes are green' and a newline
echo templatereplace($template,$replacements);


function templatereplace($template,$replacements)
{
    // our output
    $outputstring = "";

    // run through the template character by character
    for($n=0 ; $n<strlen($template) ; $n++)
    {

            // if the escaped string starts
            if($template[$n] == '{')
            {
                    // reset the name of the replacement variable
                    $replacementvar = '';

                    // set the flag
                    $escaped = 1;  

                    // next round
                    continue;
            }

            // if the escaped string part stops
            if($template[$n] == '}')
            {
                    //echo "end\n";

                    // write the replacementvariable to outputstring
                    $outputstring .= $replacements[$replacementvar];

                    // set the flag
                    $escaped = 0; 

                    // next round
                    continue;

            }

            // if we are in escapes state
            if($escaped == 1)
                    // write current char to the replacementvar
                    $replacementvar .= $template[$n];
            else    
                    // write the current char to output string
                    $outputstring .= $template[$n];

            }

        // return the output string
        return $outputstring;
}

注意:与上面的str_replace和strtr解决方案不同,这也将替换模板中存在但未在替换范围中定义的转义变量。

答案 7 :(得分:0)

所以基本上,你想要做到以下几点,但是要推迟解析&#34;解析&#34;你可以在你自己的函数中定义你的变量吗?

$foo = 'variable_string';
$baz = 'characters';

$new_string = "my {$foo}s of {$baz}s";
echo $new_string; // 'my variable_strings of characterss'

正如DCoder在他的一个答案中建议的那样,你可以使用get_defined_vars();功能并从那里开始。这是使用该方法的解决方案。

<?php

$template = '<h1>{$title}</h1><h2>{$subheading}</h2>'; 

function render($str) {
    $title = 'Delayed String Parsing';
    $subheading = 'As demonstrated by the following sample code';

    $defined_variables = get_defined_vars();

    $defined_variable_keys = array_keys($defined_variables);
    $parsed_string = $str;
    for ($i = 0; $i < count($defined_variable_keys); $i++) {
        $var_name = $defined_variable_keys[$i];
        $parsed_string = str_replace('{$' . $var_name . '}', $defined_variables[$var_name], $parsed_string);
    }
    return $parsed_string;
}

echo render($template);

您可以在此处看到它:http://ideone.com/1WMQSr

答案 8 :(得分:0)

Code Golf样式的答案是强制重新解析带有eval的字符串:

$template = '<h1>{$title}</h1><h2>{$subheading}</h2>';

$title = 'variable string';
$subheading = 'some other variable stuff';

echo eval("return \"$template\";");

当然,不要在制作中这样做。 : - )

答案 9 :(得分:0)

简单地

function map($string, $variables) {
    $mapper = array();
    foreach ($variables as $name => $value) 
        $mapper["#{$name}#"] = $value;

    return strtr($string, $mapper);
}

function render($template) {
    $foo = 'variable_string';
    $baz = 'characters';

    return map($template, get_defined_vars());  
}

echo render('#foo# 123 #baz#aaa');

答案 10 :(得分:0)

也许不能直接回答您的问题,但看起来您正在尝试构建自己的MVC引擎。如果是这种情况,我发现在控制器中定义模板(视图)然后在视图中定义逻辑(控制器)会很奇怪。我认为应该是另一种方式。

如果您这样使用它,您可以在控制器中定义所有变量,只需使用包含文件作为&#34;查看&#34;这会简化很多事情并为你提供更多控制。

<?php
class Model
{
    private $_title;
    private $_subHeading;

    final public function __construct($title, $subHeading)
    {
        $this->_title = $title;
        $this->_subheading = $subHeading;
    }

    final public function Title() { return $this->_title;   }
    final public function SubHeading() {    return $this->_subHeading;  }
}

class Controller
{
    final public function __construct()
    {
        $model = new Model("variable string","some other variable stuff");

        //in this example return isn't realy needed, but you could alter the view class to buffer the output and return it to the controller instead of just sending the output to the user directly.
        return View::Render("test.php", $model);
    }
}

class View
{
    final static public function Render($viewTemplate, $model)
    {
        //Omitted: do some checking here for file exits etc.

        //I include a masterpage first. This contains the main layout of the site and CSS/scripts etc.
        //You could expand on this to have multiple different masterpages, but for this example I kept it simple with just one.


        //you could use some output buffering around the include to be able to return the content to the controller.

        include("masterpage.php");
    }
}
?>

masterpage.php

<html>
<head>
    <title><?php echo $model->Title(); ?></title>
</head>
<body>
<?php include($viewTemplate); ?>
</body>
</html>

test.php的

<h1><?php echo $model->Title(); ?></h1><h2><?php echo $model->SubHeading(); ?></h2>

您如何调用控制器取决于您。我个人会使用.htaccess将所有请求发送到单个php文件,然后根据URL启动正确的控制器。对于简单测试,您可以使用$c = new Controller();

最终输出给用户:

<html>
<head>
    <title>variable string</title>
</head>
<body>
<h1>variable string</h1><h2>some other variable stuff</h2>
</body>
</html>