Smarty(和其他tpl ngins):分配和分配_by_ref

发布于 2024-11-03 18:21:22 字数 1724 浏览 3 评论 0原文

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

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

更具体地说:当您将控制器 ($a) 中的一个大数组分配给模板引擎 ($tpl->vars['a']) 并在视图中使用(提取$a)? PHP 的内存增加了三倍吗?

现在,如果我通过引用分配所有变量会发生什么?我很高兴我的观点能够将阵列更改回控制器(无论如何我都不会回到那里)。如果变量在模板引擎内发生变化也没关系($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

This is not just about Smarty, but I guess most template engines that have variables assigned. It's more a theoretical question, than a practical. I have no use case.

What happens in PHP when you assign a big array $a to another variable $b? PHP copies the array? Maybe, just maybe, internally it creates a pointer. Then what happens when you alter $a slightly? $b shouldn't be changed, because no & was used to create $b. Did PHP just double the memory usage??

More specifically: What happens when you assign a big array from you Controller ($a) to your template engine ($tpl->vars['a']) and to use in the view (extract to $a)? Did PHP's memory just triple??

Now what happens if I assign all my variables by reference? I'm cool with my view being able to alter the array back into the Controller (I won't be coming back there anyway). It's also fine if the variable changes within the templat engine ($tpl->vars['a']).

Is assigning all vars by reference better for memory? Better for performance? If so: any chances of strange, unwanted side effects?

Because people like code and not stories:

// 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?
}

I'm pretty sure PHP doesn't mind big arrays and copies and clones, but performance and memory wise: which's 'better'?

edit
For objects, all of this doesn't matter. Objects are always, automatically assigned by reference. And since objects are hot, maybe this is an outdated question, but I am very curious.

UPDATE
So PHP uses copy on write... Love it. And objects are always pointers. What happens when you:

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

Did this trigger the copy-on-write? Or are $a and $b still identical (like in ===)?

edit
Could I conclude that assigning by ref is really not worth it just to spare memory? PHP in itself is smart enough?

edit
Interesting visualization of copy, clone, by-ref etc: http://www.phpinsider.com/download/PHP5RefsExplained.pdf

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冷血 2024-11-10 18:21:22

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

现在,如果$a$b 被修改,值显然不能再共享,必须复制。

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

一些进一步的注意事项:

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

    $a = SOMETHING_BIG; // $a 指向 refcount 为 1 且 is_ref 为 0 的 zval
    $b = $a; // $a 和 $b 都指向 refcount 为 2 且 is_ref 为 0 的 zval
    $c =& $a; // 现在我们有一个问题:$c 不能只指向同一个 zval
                        // 不再这样了,因为 zval 的 is_ref 为 0,但我们需要一个
                        // with is_ref 1. 因此 zval 被复制。您现在有 $b
                        // 指向一个 zval,refcount 为 1,is_ref 为 0,$a 和
                        // $c 指向另一个引用计数为 2 且 is_ref 为 1 的引用
    

    所以实际情况与你想要的相反。您实际上不是在节省内存,而是在分配额外的内存。通常很难判断添加引用是否会使情况变得更好或更糟,因为通常很难跟踪指向一个 zval 的所有不同变量(这通常不像看起来那么容易,只需看一下 debug_zval_dump 函数 因此,实际上,这是了解引用是否有利于性能的唯一安全方法。或不,是实际分析这两种变体。

  • 与其他事物一样,对象在 PHP 中通过值传递。尽管如此,你还是对的,它们的行为就像引用一样,因为对于对象来说,传递的这个值只是指向其他数据结构的指针。在大多数情况下,通过引用传递和类引用行为之间的区别并不重要,但仍然存在差异。

这只是对该主题的简短介绍。您可以在 博客中找到对该主题的更深入分析Sara Golemon 的帖子,标题是“你被骗了”

PHP uses a concept called copy on write. I.e. if you just do a $a = $b PHP will not copy the whole value of $b to $a. It will just create some kind of a pointer. (To be more precise both $a and $b will point to the same zval and it's refcount will be increased.)

Now, if either $a or $b were modified the value obviously can't be shared anymore and must be copied.

So, unless you aren't modifying the array in your template code, no copying will be done.

Some further notes:

  • Beware of trying to optimize your code by blindly inserting references. Often they will have an effect contrary to what you expect. Example to explain why:

    $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
    

    So the contrary to what you wanted actually happened. Instead of saving memory you are actually allocating additional. It's often hard to judge whether adding a reference will make it better or worse because it's often hard to trace all different variables pointing to one zval (it's often not as easy as it looks, just have a look at the examples of the debug_zval_dump function. So, really, the only safe way to know, whether a reference is good for performance or not, is to actually profile both variants.

  • Objects are, just like everything else, passed by value in PHP. Still you are right that they behave reference-like, because with objects this value that get's passed around is just a pointer to some other data structure. In most cases the distinction between passing by reference and reference-like behavior isn't of importance, but there still is a difference.

This was just a short introduction to the topic. You can find a more in-depth analysis of the topic in a blog post by Sara Golemon with the porvoking title "You're being lied to".

孤独岁月 2024-11-10 18:21:22

正如其他答案中提到的,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 也会受到影响。从来没有涉及任何对象的复制。

As mentioned in other answers, PHP employs copy-on-write. However I do wish to answer this part of your post:

Objects are always, automatically
assigned by reference.

This is not entirely true. They are assigned an identifier which points to an object.

$a = new stdClass();
$b = $a; // $a and $b now share same identifier
$b = 0; // $b no longer contains identifier
var_dump($a); // outputs object

Contrast this with assigning by reference:

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

Update

In your edit you ask:

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

Did this trigger the copy-on-write? Or
are $a and $b still identical (like in
===)?

Because $b now contains an identifier, i.e. now "points" to same object as $a, $a is also affected. There was never any copying of objects involved.

疧_╮線 2024-11-10 18:21:22

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

PHP uses copy-on-write when passing arrays around, so no extra memory is used until you modify the array. Sorry, no link to back up this claim.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文