【问题标题】:Smarty assignByRef inside loopSmarty assignByRef 内循环
【发布时间】:2016-11-24 15:57:36
【问题描述】:

我需要为循环内的不同值呈现一些 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 文档说:

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

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

【问题讨论】:

    标签: php smarty pass-by-reference


    【解决方案1】:

    PHP 4 对象是按值传递的,,除非用户通过添加 & 符号明确指定引用:&amp;$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 及更高版本中的任何函数参数。

    【讨论】:

    • 好的。你的最后一段是我问题的答案。我知道 PHP 实现了写时复制策略,但我不知道PHP &lt; v5.0 不是这样。
    • 那个写时复制策略,也适用于数组元素?我的意思是,如果我将数组传递给对象的函数并将数组保存在内部变量中,并在for 中更改每个循环上的一些值(例如,v[i] = i),PHP 是否应用在原始数组上进行深度复制?换句话说,对象会看到外部变化吗?因为“传递的写时复制值”没有改变,而是它的内容。
    • @Peregring-lk,数组项本身就是zvals。 PHP 将只为修改过的项目创建副本,无论范围如何。
    猜你喜欢
    • 1970-01-01
    • 2014-02-20
    • 2016-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多