2

问题

我想以与扩展双引号字符串中的变量相同的方式扩展字符串中的变量。

$string = '<p>It took $replace s</>';
$replace = 40;
expression_i_look_for;

$string应该成为'<p>It took 40 s</>';

我看到一个明显的解决方案是这样的:

$string = str_replace('"', '\"', $string);
eval('$string = "$string";');

但我真的不喜欢它,因为 eval() 是不安全的。有没有其他方法可以做到这一点?

语境

我正在构建一个简单的模板引擎,这就是我需要的地方。

示例模板 (view_file.php)

<h1>$title</h1>
<p>$content</p>

模板渲染(简化代码):

$params = array('title' => ...);

function render($view_file, $params)
    extract($params)
    ob_start();
    include($view_file);
    $text = ob_get_contents();
    ob_end_clean();
    expression_i_look_for; // this will expand the variables in the template
    return $text;
}

模板中变量的扩展简化了它的语法。没有它,上面的示例模板将是:

<h1><?php echo $title;?></h1>
<p><?php echo $content;?></p>

你觉得这种方法好吗?还是我应该往另一个方向看?

编辑

最后我明白,由于 PHP 扩展变量的灵活方式(即使${$var}->member[0]是有效的),没有简单的解决方案。

所以只有两种选择:

  1. 采用现有的成熟模板系统
  2. 坚持一些非常基本的东西,基本上仅限于通过include.
4

7 回答 7

4

我宁愿建议使用一些现有的模板引擎,例如 Smarty,但如果你真的想自己做,你可以使用简单的正则表达式来匹配所有用字母和数字构造的变量,然后用正确的变量替换它们:

<?php

$text = 'hello $world, what is the $matter? I like $world!';

preg_match_all('/\$([a-zA-Z0-9]+)/',
    $text,
    $out, PREG_PATTERN_ORDER);

$world = 'World';
$matter = 'matter';

foreach(array_unique($out[1]) as $variable){
    $text=str_replace('$'.$variable, $$variable, $text);
}

echo $text;

?>

印刷

你好世界,怎么了?我喜欢世界!

于 2013-09-04T16:49:26.977 回答
1

你想这样做吗?

模板.php:

<?php

$first = "first";
$second = "second";
$third = "third";

include('template.php');

模板.php:

<?php

echo 'The '.$first.', '.$second.', and '.$third.' variables in a string!';

运行时templater.php,产生:

"The first, second, and third variables in a string!"
于 2013-09-04T16:41:15.557 回答
1

解析

解析字符串查找$后跟有效的变量名(即\[a-zA-Z_\x7f-\xff\]\[a-zA-Z0-9_\x7f-\xff\]*

变量²

使用变量变量语法(即$$var表示法)。

于 2013-09-04T16:49:19.903 回答
0

而不是使用单引号

$string = '<p>It took $replace s</>';
$replace = 40;

使用双引号

$replace = 40;
$string = "<p>It took $replace s</>";

但是,为了便于阅读并使您能够删除 $replace 和我将使用的 s 之间的空格:

$replace = 40;
string = '<p>It took ' . $replace . 's</>';
于 2013-09-04T16:47:04.460 回答
0

你想要这样的东西吗?

$replace = 40;
$string = '<p>It took {$replace}s</p>';
于 2013-09-04T16:45:06.367 回答
0

正确的方法可能是将您的文档解析为一棵树,识别您的解析器标签(因为您正在管理自己的解析器,如果您不希望它们遵循 php 约定,则它们不必遵循),然后添加您的值当机会出现时,关联数组或其他数据结构。

这是一个更复杂的解决方案,但是当您意识到您希望能够使用某种基于标准显示选项的循环结构提前显示长度未知的列表时,它会变得更容易。从长远来看,您不会发现许多严肃的模板系统不会将文档解析为某种内存树,在其中可以插入占位符,然后根据需要构造文档。这也为缓存提供了许多机会。此外,如果您不怕递归,您将能够相当简单地对其执行大量操作。

然而,这并不是一个不常见的问题,正如我在这个问题上评论的那样,几乎可以保证有一些库和扩展可以提供你需要的大部分功能。除非这对你来说是一个纯粹的学术过程,否则我会找到一些现有的解决方案,或者使用其中一个,或者深入了解它的工作原理,这样你就有一个调整自己的解决方案的起点。

于 2013-09-04T16:49:07.890 回答
0

这是我从 Lejlot 的回答中提取的一个片段。我测试了它,它工作正常。

function resolve_vars_in_str( $input )
{
    preg_match_all('/\$([a-zA-Z0-9]+)/', $input, $out, PREG_PATTERN_ORDER);
    foreach(array_unique($out[1]) as $variable) $input=str_replace('$'.$variable, $GLOBALS["$variable"], $input);
    return $input ;
}
于 2016-06-23T16:11:14.337 回答