Smarty(和其他tpl ngins):assign和assign_by_ref

Rud*_*die 3 php template-engine smarty pass-by-reference

这不只是关于Smarty,但我猜大多数模板引擎都有变量分配.这更像是一个理论问题,而不是一个实际问题.我没有用例.

将大数组分配$a给另一个变量时,PHP会发生什么$b?PHP复制数组?也许,只是可能,在内部它创建一个指针.那么当你$a稍微改变一下会发生什么?$b不应该改变,因为没有&用来创建$b.PHP只是内存使用量的两倍?

更具体地说:当您从Controller($a)向模板引擎($tpl->vars['a'])分配大数组并在视图(extractto $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?
}
Run Code Online (Sandbox Code Playgroud)

我很确定PHP不介意大数组,副本和克隆,但性能和内存明智:哪个'更好'?

编辑
对于对象,所有这些都无关紧要.始终通过引用自动分配对象.而且,由于对象是热的,也许这是一个过时的问题,但我感到很好奇.

更新
所以PHP使用copy on write...喜欢它.对象总是指针.当你:

$a = new BigObject;
$b = $a; // pointer, right?
$b->updateSomethingInternally(); // $b is now changed > what about $a?
Run Code Online (Sandbox Code Playgroud)

这是否触发了写时复制?或者$ a和$ b仍然相同(如in ===)?

编辑
我可以得出结论,由ref分配真的不值得它只是为了节省内存吗?PHP本身就足够聪明了?

编辑
复制,克隆,副作用等有趣的可视化:http://www.phpinsider.com/download/PHP5RefsExplained.pdf

Nik*_*kiC 6

PHP使用一种名为copy on write的概念.也就是说,如果你只是做一个$a = $bPHP将不可复制的全部价值$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
    
    Run Code Online (Sandbox Code Playgroud)

    所以与你想要的实际情况相反.而不是保存记忆,你实际上是分配额外的.通常很难判断添加引用是否会使其更好或更差,因为通常很难跟踪指向一个zval的所有不同变量(它通常不像它看起来那么容易,只需查看debug_zval_dump函数的示例.所以实际上,唯一安全的方法是知道参考是否对性能有益,实际上是对这两种变体进行分析.

  • 对象就像其他一切一样,在PHP中通过值传递.你仍然是正确的,他们的行为类似于引用,因为对于对象,这个传递的值只是指向其他一些数据结构的指针.在大多数情况下,通过引用传递和类似引用的行为之间的区别并不重要,但仍然存在差异.

这只是对该主题的简短介绍.您可以在Sara Golemon博客文章中找到对该主题的更深入的分析,其标题是"你被骗了".