php - Smarty(和其他 tpl ngins): assign and assign_by_ref

标签 php smarty pass-by-reference template-engine

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

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

更具体地说:当您将一个大数组从 Controller ($a) 分配给您的模板引擎 ($tpl->vars['a'] ) 并在 View 中使用(extract$a)? PHP 的内存只是增加了三倍吗??

现在如果我通过引用分配所有变量会发生什么?我很高兴我的观点能够将数组改回 Controller (无论如何我都不会回到那里)。如果变量在模板引擎 ($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 使用 copy on write... 喜欢它。对象总是指针。当您:

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

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

编辑
我可以得出结论,仅仅为了节省内存,通过 ref 分配真的不值得吗? PHP 本身是否足够智能?

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

最佳答案

PHP 使用一种称为写时复制的概念。 IE。如果您只是执行 $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 的所有不同变量(它通常不像看起来那么容易,只要看看 debug_zval_dump 的示例)功能。因此,真正了解引用是否对性能有益的唯一安全方法是实际分析这两种变体。

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

这只是对该主题的简短介绍。您可以在 blog post by Sara Golemon with the porvoking title "You're being lied to" 中找到对该主题的更深入分析。 .

关于php - Smarty(和其他 tpl ngins): assign and assign_by_ref,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5794746/

相关文章:

php - 如何在 Laravel 5.7 中限制对数据库的数据输入

php - USPS API 返回 80040B19 错误代码并且帐户正在生产中

php - Joomla 到静态 HTML 网站

php - 带字符串的 Smarty 局部变量连接

php - 聪明人 : evaluate a template stored in a PHP variable

c++ - 为什么这个程序使用 boost::ref

php - html 页面上方的静态消息

php - 这个sql IF语句是如何工作的?

C#:对包含 List<string> 的变量的属性的初始分配会在稍后对同一变量使用 RemoveAll 时更新

c++ - 带有 *& 参数的函数中的 Const 关键字。