Smarty assignByRef内循环

时间:2016-11-24 15:57:36

标签: php smarty pass-by-reference

我需要为循环内的不同值渲染一些 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);
}

我怀疑是assignByRef Smarty v3 文档说:

  

随着PHP5的推出,大多数人都不需要assignByRef()   意图和目的。如果你想要一个PHP数组,assignByRef()很有用   受模板重新分配影响的索引值。   默认情况下,分配的对象属性以这种方式运行。

但我并不完全明白该技术说明的含义。那么,我可以这样使用assignByRef吗?或仅使用assign将产生相同的输出?

1 个答案:

答案 0 :(得分:1)

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

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

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

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

第一行为变量$astdClass对象分配内存,并将对象的标识符存储到变量中。第二行为变量$b分配内存,将对象的标识符存储到$b变量中,并递增内部引用计数器。引用计数器值显示代码中引用对象的次数。当$b变量被销毁时,引用计数器减1。当参考计数器的值变为等于零时,对象的存储器被解除分配。以下代码演示了这个想法:

$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及更高版本中的任何函数参数。