Smarty assignByRef 内部循环

Smarty assignByRef inside loop

我需要为循环内的不同值渲染一些 Smarty 模板(PHP 循环,而不是 Smarty foreach), 方式如下(仅举个例子):

$a = 0;
$b = 0;
$output = "";
$tmpl = "$a, $b";

$smarty->assignByRef('a', $a['a']);
$smarty->assignByRef('b', $b['b']);

for (int i = 0; i < 10; ++i) {
   ++$a;
   ++$b;

   $output .= $smarty->fetch("string:" . $tmpl);
}

我的疑问是assignByRefSmarty v3 文档说:

With the introduction of PHP5, assignByRef() is not necessary for most intents and purposes. assignByRef() is useful if you want a PHP array index value to be affected by its reassignment from a template. Assigned object properties behave this way by default.

但我不完全理解该技术说明的含义。那么,我可以这样使用 assignByRef 吗?或者只使用 assign 会产生相同的输出?

PHP 4 个对象被 按值 传递,除非用户通过前置 & 符号明确指定引用:&$variable。出于这个原因,可能会消耗大量内存的函数参数通过引用传递以优化内存使用:

function f(&$huge) {
  // ...
}

PHP 5 个变量通过引用传递,即使用户没有明确指定它(未使用 & 字符)。通过将一个变量分配给另一个变量,我们只是为内存中的相同数据创建了一个新容器(内部称为 zval)。考虑一下:

$a = new stdClass;
$b = $a;

第一行为变量$astdClass的对象分配内存,并将对象的标识符存储到变量中。第二行为变量 $b 分配内存,将对象的标识符存储到 $b 变量中,并增加一个内部引用计数器。引用计数器值显示对象在代码中被引用了多少次。当 $b 变量被销毁时,引用计数器减一。当引用计数器的值变为零时,对象的内存将被释放。下面的代码演示了这个想法:

$a = new stdClass;
debug_zval_dump($a);
$b = $a;
debug_zval_dump($a);
$c = $a;
debug_zval_dump($a);
$c = null; // destroy $c
debug_zval_dump($a);
$b = null; // destroy $b
debug_zval_dump($a);

输出

object(stdClass)#1 (0) refcount(2){
}
object(stdClass)#1 (0) refcount(3){
}
object(stdClass)#1 (0) refcount(4){
}
object(stdClass)#1 (0) refcount(3){
}
object(stdClass)#1 (0) refcount(2){
}

但是当变量被修改时,PHP版本 5 和 7 会创建变量的副本,以保持原始值(变量)不变。

$m1 = memory_get_usage();

$a = str_repeat('a', 1 << 24);
echo number_format(memory_get_usage() - $m1), PHP_EOL;
// 16,781,408

$b = $a;
$c = $a;
echo number_format(memory_get_usage() - $m1), PHP_EOL;
// 16,781,472

$b[0] = 'x';
echo number_format(memory_get_usage() - $m1), PHP_EOL;
// 33,562,880

$c[0] = 'x';
echo number_format(memory_get_usage() - $m1), PHP_EOL;
// 50,344,288

这同样适用于函数参数的上下文。因此,如果一个变量应该用于只读,则不需要显式地通过引用传递它。 Smarty 文档中的话意味着在大多数情况下,您将变量传递给模板,并且通常不希望模板更改它们。仅当您确实希望在模板中修改变量时才需要通过引用传递变量。同样的概念适用于 PHP 5 和更新版本中的任何函数参数。