对于这种PHP按值调用行为,是否有合理的解释?还是PHP错误? [英] Is there a rational explanation for this PHP call-by-value behavior? Or PHP bug?

查看:49
本文介绍了对于这种PHP按值调用行为,是否有合理的解释?还是PHP错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

PHP 5.5.12。考虑一下:

PHP 5.5.12. Consider this:

<?php
$a = [ 'a', 'b', 'c' ];
foreach($a as &$x) {
    $x .= 'q';
}
print_r($a);

正如预期的那样,输出:

This, as expected, outputs:

Array
(
    [0] => aq
    [1] => bq
    [2] => cq
)

现在考虑:

<?php
$a = [ 'a', 'b', 'c' ];
foreach(z($a) as &$x) {
    $x .= 'q';
}
print_r($a);

function z($a)
{
    return $a;
}

此输出:

Array
(
    [0] => aq
    [1] => bq
    [2] => cq
)

(!)但是请稍等。 $ a未通过引用传递。这意味着我应该从z()得到一个副本,该副本将被修改,并且$ a应该单独放置。

(!) But wait a minute. $a is not being passed by reference. Which means I should be getting a copy back from z(), which would be modified, and $a ought to be left alone.

但是当我们强制使用PHP时会发生什么?做它的写时复制魔术:

But what happens when we force PHP to do its copy-on-write magic:

$a = [ 'a', 'b', 'c' ];
foreach(z($a) as &$x) {
    $x .= 'q';
}
print_r($a);

function z($a)
{
    $a[0] .= 'x';
    return $a;
}

为此,我们得到了我期望的结果:

For this, we get what I would expect:

Array
(
    [0] => a
    [1] => b
    [2] => c
)

编辑:另一个示例...

One more example...

$a = [ 'a', 'b', 'c' ];
$b = z($a);
foreach($b as &$x) {
    $x .= 'q';
}
print_r($a);

function z($a)
{
    return $a;
}

这可以按预期工作:

Array
(
    [0] => a
    [1] => b
    [2] => c
)

对此是否有合理的解释?

Is there a rational explanation for this?

推荐答案

更新



错误 67633 已打开,可以解决此问题。该行为已由此提交进行了更改,旨在从foreach中删除引用限制。

Update

Bug 67633 has been opened to address this issue. The behaviour has been changed by this commit in an effort to remove reference restrictions from foreach.

来自此3v4l输出,您可以清楚地看到这种行为已随着时间而改变:

From this 3v4l output you can clearly see that this behaviour has changed over time:

已通过此提交修复。这将在5.5.18和5.6.2中提供。

Fixed with this commit; this will become available in 5.5.18 and 5.6.2.

PHP 5.5之前的版本代码实际上会引发致命错误:

Prior to PHP 5.5 your code would actually raise a fatal error:

Fatal error: Cannot create references to elements of a temporary array expression



PHP 5.5-5.6



当直接在 foreach 块内使用函数结果时,这些版本不执行写时复制。这样,现在就可以使用原始数组,并且对元素的更改是永久的。

PHP 5.5 - 5.6

These versions do not perform copy-on-write when the function result is used directly inside the foreach block. As such, the original array is now used and changes to the elements are permanent.

我个人认为这是一个错误

phpng分支,它很可能会成为下一个主要版本的基础,常量数组是不可变的,因此仅在这种情况下才能正确执行写时复制。像下面这样声明数组将对phpng造成同样的问题:

In the phpng branch, which is likely to become the basis of a next major version, constant arrays are made immutable so the copy-on-write is correctly performed only in this case. Declaring the array like below will exhibit the same issue with phpng:

$foo = 'b';
$a = ['a', $foo, 'b'];

证明

只有Hack可以正确处理当前情况。

Only Hack handles the situation correctly as it currently stands.

已记录通过引用使用函数结果的方式是:

The documented way of using the function result by reference is this:

$a = [ 'a', 'b', 'c' ];
foreach(z($a) as &$x) {
    $x .= 'q';
}
print_r($a);

// indicate that this function returns by reference 
// and its argument must be a reference too
function &z(&$a)
{
    return $a;
}

演示

到避免更改原始数组,现在,您可以使用以下选项:

To avoid changing the original array, for now, you have the following options:


  1. 将函数结果分配给临时变量 before foreach ;

  2. 不使用引用;

  3. 切换到Hack

  1. Assign the function result into a temporary variable before the foreach;
  2. Don't use references;
  3. Switch to Hack.

这篇关于对于这种PHP按值调用行为,是否有合理的解释?还是PHP错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆