Php Smarty(和其他tpl NGIN):分配和分配\u

Php Smarty(和其他tpl NGIN):分配和分配\u,php,smarty,pass-by-reference,template-engine,Php,Smarty,Pass By Reference,Template Engine,这不仅仅是Smarty的问题,我想大多数模板引擎都分配了变量。这与其说是一个实际问题,不如说是一个理论问题。我没有用例 当您将一个大数组$a分配给另一个变量$b时,在PHP中会发生什么?PHP复制数组?也许,只是也许,它在内部创建了一个指针。那么,当您稍微更改$a时会发生什么情况$b不应更改,因为没有使用&创建$b。PHP的内存使用率是原来的两倍吗 更具体地说:当您从控制器($a)将一个大数组分配给模板引擎($tpl->vars['a'])并在视图中使用(提取到$a)时会发生什么?PHP的内存是

这不仅仅是Smarty的问题,我想大多数模板引擎都分配了变量。这与其说是一个实际问题,不如说是一个理论问题。我没有用例

当您将一个大数组
$a
分配给另一个变量
$b
时,在PHP中会发生什么?PHP复制数组?也许,只是也许,它在内部创建了一个指针。那么,当您稍微更改
$a
时会发生什么情况<代码>$b不应更改,因为没有使用
&
创建
$b
。PHP的内存使用率是原来的两倍吗

更具体地说:当您从控制器(
$a
)将一个大数组分配给模板引擎(
$tpl->vars['a']
)并在视图中使用(
提取到
$a
)时会发生什么?PHP的内存是原来的三倍吗

现在,如果我通过引用分配所有变量,会发生什么?我对我的视图能够将阵列更改回控制器很酷(反正我不会再回来了)。如果变量在templat引擎中发生更改(
$tpl->vars['a']
),也可以

通过引用分配所有变量是否更利于内存?性能更好?如果是这样:有没有可能出现奇怪的、不必要的副作用

因为人们喜欢代码而不是故事:

// copies
$a = array( ... );
$tpl->assign('a', $a); // creates a copy (?) in $tpl->vars['a']

// pointer / by ref
$a = array( ... );
$tpl->assign_by_ref('a', $a); // creates a pointer in $tpl->vars['a'] because:

function assign_by_ref( $name, &$var ) {
  $this->vars[$name] = $var; // voila pointer?
}
我很确定PHP并不介意大的数组、拷贝和克隆,但在性能和内存方面:哪一个更好

编辑
对于对象,所有这些都无关紧要。对象始终通过引用自动指定。由于物体是热的,也许这是一个过时的问题,但我非常好奇

更新
因此PHP使用
写时复制
。。。我喜欢。对象总是指针。当您:

$a = new BigObject;
$b = $a; // pointer, right?
$b->updateSomethingInternally(); // $b is now changed > what about $a?
这是否触发了写入时的复制?或者$a和$b是否仍然相同(如在
=
中)

编辑
我能否得出结论,仅仅为了节省内存,按ref赋值真的不值得?PHP本身足够聪明吗

编辑

复制、克隆、按引用等的有趣可视化:

PHP在传递数组时使用写时复制,因此在修改数组之前不会使用额外的内存。很抱歉,没有链接支持此声明。

PHP使用了一个名为“写时复制”的概念。也就是说,如果只执行a
$a=$b
PHP将不会将
$b
的整个值复制到
$a
。它只会创建某种指针。(更准确地说,
$a
$b
都将指向相同的zval,并且它的
refcount
将增加。)

现在,如果修改了
$a
$b
,则该值显然无法再共享,必须复制

因此,除非您不在模板代码中修改数组,否则不会进行复制

一些进一步的说明:

  • 注意不要试图通过盲目插入引用来优化代码。通常,它们会产生与您预期相反的效果。举例说明原因:

    $a = SOMETHING_BIG; // $a points to a zval with refcount 1 and is_ref 0
    $b = $a;            // $a and $b both point to a zval with refcount 2 and is_ref 0
    $c =& $a;           // Now we have a problem: $c can't just point to the same zval
                        // anymore, because that zval has is_ref to 0, but we need one
                        // with is_ref 1. So The zval gets copied. You now have $b
                        // pointing to one zval with refcount 1 and is_ref 0 and $a and
                        // $c pointing to another one with refcount 2 and is_ref 1
    
    事实上,与你所希望的相反。实际上,您不是在节省内存,而是在分配额外的内存。通常很难判断添加引用是否会使它变得更好或更糟,因为通常很难跟踪指向一个zval的所有不同变量(这通常不像看上去那么简单,只要看看函数的示例就可以了。因此,实际上,了解引用是否有利于性能的唯一安全方法是实际分析这两种变体

  • 在PHP中,对象和其他所有对象一样,都是按值传递的。但您仍然认为它们的行为类似于引用,这是正确的,因为对于对象来说,传递的这个值只是指向其他数据结构的指针。在大多数情况下,按引用传递和类似引用的行为之间的区别并不重要,但仍然存在差异这是不同的

这只是对该主题的一个简短介绍。您可以在a中找到对该主题的更深入分析。

如其他答案中所述,PHP采用书面复制。不过,我确实希望回答您文章的这一部分:

对象始终是自动的 通过引用分配

这并不完全正确。它们被分配了一个指向对象的标识符

$a = new stdClass();
$b = $a; // $a and $b now share same identifier
$b = 0; // $b no longer contains identifier
var_dump($a); // outputs object
将此与通过引用指定进行对比:

$a = new stdClass();
$b =& $a; // $a and $b now share same reference
$b = 0; //
var_dump($a); // outputs int(0)
更新

在编辑过程中,您会问:

$a = new BigObject;
$b = $a; // pointer, right?
$b->updateSomethingInternally(); // $b is now changed > what about $a?
这是否触发了写入时的复制?或者 $a和$b是否仍然相同(如中所示) ===)


由于
$b
现在包含一个标识符,即现在“指向”与
$a
相同的对象,
$a
也会受到影响。从未涉及任何对象复制。

哇……这比我预期的要高级一点=),但我看到了要点(以及示例中的问题)。我知道PHP是个聪明的母亲!我正在用一个额外的问题更新我原来的问题=)@Rudie:我更新了我的答案,加入了一段关于对象的内容。但在您的示例中,
$a
$b
都将更改。这是可以看到类似引用行为的情况之一。看看webbiedave的答案,看看一个例子,证明它不是一个真正的参考。有趣的是,我不知道这一点!这是一个非常好的观点!这不是新闻,而是一个很好的观点。我只是指包含对象的变量的内容。谢谢nikic。忘记了那个代码块。解决你上次编辑的问题:是的,不值得。PHP在一般情况下足够聪明。此外:你根本不应该担心这一点,记忆通常是没有问题的网站。