我的PHP引用数组"神奇"成为值的数组...为什么? [英] My PHP array of references is "magically" becoming an array of values... why?

查看:176
本文介绍了我的PHP引用数组"神奇"成为值的数组...为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要创建周围的mysqli的包装功能,使我的应用程序不必与数据库的处理code过于复杂。那部分是位code的SQL调用使用的mysqli :: bind_param参数化()。 bind_param(),因为你可能知道,需要引用。因为它是一个半通用的包装,我最终作出这一呼吁:

I'm creating a wrapper function around mysqli so that my application needn't be overly complicated with database-handling code. Part of that is a bit of code to parameterize the SQL calls using mysqli::bind_param(). bind_param(), as you may know, requires references. Since it's a semi-general wrapper, I end up making this call:

call_user_func_array(array($stmt, 'bind_param'), $this->bindArgs);

和我得到一个错误信息:

and I get an error message:

Parameter 2 to mysqli_stmt::bind_param() expected to be a reference, value given

以上的讨论是福斯代尔那些谁也说:你不要在需要引用了所有在你的榜样。

The above discussion is to forstall those who would say "You don't need references at all in your example".

我的真正的code是比任何人想读比较复杂一点,所以我煮code导致这一错误为以下(希望)说明性的例子:

My "real" code is a bit more complicated than anyone wants to read, so I've boiled the code leading up to this error into the following (hopefully) illustrative example:

class myclass {
  private $myarray = array();

  function setArray($vals) {
    foreach ($vals as $key => &$value) {
      $this->myarray[] =& $value;
    }
    $this->dumpArray();
  }
  function dumpArray() {
    var_dump($this->myarray);
  }
}

function myfunc($vals) {
  $obj = new myclass;
  $obj->setArray($vals);
  $obj->dumpArray();
}

myfunc(array('key1' => 'val1',
             'key2' => 'val2'));

这个问题似乎是,在MYFUNC(),在调用setArray()的调​​用与对dumpArray()之间,在$所有元素obj-> myArray的不再是引用,并成为正义价值观来代替。这可以通过在输出很容易地看到:

The problem appears to be that, in myfunc(), in between the call to setArray() and the call to dumpArray(), all the elements in $obj->myarray stop being references and become just values instead. This can be easily seen by looking at the output:

array(2) {
  [0]=>
  &string(4) "val1"
  [1]=>
  &string(4) "val2"
}
array(2) {
  [0]=>
  string(4) "val1"
  [1]=>
  string(4) "val2"
}

请注意,数组是正确的状态,在这里输出的前半部分。如果这是有道理的话,我可以让我的bind_param()调用在这一点上,它会工作。不幸的是,事情打破了输出的后半段。注意缺乏的与&在数组值类型。

Note that the array is in the "correct" state in the first half of the output here. If it made sense to do so, I could make my bind_param() call at that point, and it would work. Unfortunately, something breaks in the latter half of the output. Note the lack of the "&" on the array value types.

发生了什么事我引用?我怎样才能prevent这种情况发生?我讨厌叫PHP错误时,我真的不是语言专家,但会这样呢?它似乎很奇怪我。我使用PHP 5.3.8我此刻的测试。

What happened to my references? How can I prevent this from happening? I hate to call "PHP bug" when I'm really not a language expert, but could this be one? It does seem very odd to me. I'm using PHP 5.3.8 for my testing at the moment.

编辑:

由于超过一人所指出的,解决方法是改变setArray()引用来接受它的参数:

As more than one person pointed out, the fix is to change setArray() to accept its argument by reference:

function setArray(&$vals) {

我加入这个笔记记录为什么这似乎工作。

I'm adding this note to document WHY this seems to work.

PHP一般,和mysqli的特别,似乎有一个什么样的参考是一个有点奇怪的概念。注意这个例子:

PHP generally, and mysqli in particular, appear to have a slightly odd concept of what a "reference" is. Observe this example:

$a = "foo";
$b = array(&$a);
$c = array(&$a);
var_dump($b);
var_dump($c);

首先,我敢肯定你想知道为什么我使用数组而不是标量变量 - 这是因为的var_dump()不显示的标量是否是参考任何迹象,但它确实为数组成员。

First of all, I'm sure you're wondering why I'm using arrays instead of scalar variables -- it's because var_dump() doesn't show any indication of whether a scalar is a reference, but it does for array members.

反正在这一点上,$ B [0]和$ C [0]都引用$一个。到现在为止还挺好。现在我们把我们的第一个扳手插入作品:

Anyway, at this point, $b[0] and $c[0] are both references to $a. So far, so good. Now we throw our first wrench into the works:

unset($a);
var_dump($b);
var_dump($c);

$ B [0]和$ C [0]都以同样的事情还是引用。如果我们换一个,两个还是会换。但什么是他们引用?一些无名位置在存储器中。当然,垃圾收集确保我们的数据是安全的,并且将继续这样做,直到我们停下指的是它。

$b[0] and $c[0] are both still references to the same thing. If we change one, both will still change. But what are they references to? Some unnamed location in memory. Of course, garbage collection insures that our data is safe, and will remain so, until we stop refering to it.

有关我们的下一个把戏,我们这样做:

For our next trick, we do this:

unset($b);
var_dump($c);

现在$ C [0]仅存参考我们的数据。而且,哇!奇妙的是,它不再是一个参考。不是的var_dump()的措施,而不是通过mysqli的:: bind_param()的措施,无论是。

Now $c[0] is the only remaining reference to our data. And, whoa! Magically, it's no longer a "reference". Not by var_dump()'s measure, and not by mysqli::bind_param()'s measure either.

借助 PHP手册说,有一个单独的标志,对每一块数据is_ref。然而,这个测试似乎表明,is_ref实际上相当于'(引用计数> 1)

The PHP manual says that there's a separate flag, 'is_ref' on every piece of data. However, this test appears to suggest that 'is_ref' is actually equivalent to '(refcount > 1)'

为了好玩,你可以按如下修改该玩具的例子:

For fun, you can modify this toy example as follows:

$a = array("foo");
$b = array(&$a[0]);
$c = array(&$a[0]);

var_dump($a);
var_dump($b);
var_dump($c);

注意的所有三个的阵列有其成员的参考标记,用于备份的想法,is_ref在功能上等同于'(引用计数> 1)。

Note that all three arrays have the reference mark on their members, which backs up the idea that 'is_ref' is functionally equivalent to '(refcount > 1)'.

这超出了我为什么mysqli的:: bind_param()会在意这种区别在首位(或者也许是call_user_func_array()......无论哪种方式),但它会出现什么,我们确实需要确保是引用计数是至少的 2 的对我们call_user_func_array()调用$这个 - > bindArgs每个成员(见职位/问题的开始)。和最容易的方式(在这种情况下)是使setArray()传递通过引用

It's beyond me why mysqli::bind_param() would care about this distinction in the first place (or perhaps it's call_user_func_array()... either way), but it would appear that what we "really" need to ensure is that the reference count is at least 2 for each member of $this->bindArgs in our call_user_func_array() call (see the very beginning of the post/question). And the easiest way to do that (in this case) is to make setArray() pass-by-reference.

编辑:

有关额外的乐趣和游戏,我修改了原来的程序(这里没有显示),以它的等效离开setArray()传递由值,并创建一个免费的额外的阵列,bindArgsCopy,正好包含同样的事情bindArgs 。这意味着,是的,​​两个阵列包含到这是由第二个电话的时间释放临时的数据引用。正如上述分析pdicted $ P $,这个工作。这表明,上述分析不是的var_dump()的内部运作(一种解脱对我来说,至少)的神器,它也证明了它的引用计数的事项,而不是原来的临时性数据存储

For extra fun and games, I modified my original program (not shown here) to leave its equivalent to setArray() pass-by-value, and to create a gratuitous extra array, bindArgsCopy, containing exactly the same thing as bindArgs. Which means that, yes, both arrays contained references to "temporary" data which was deallocated by the time of the second call. As predicted by the analysis above, this worked. This demonstrates that the above analysis is not an artifact of var_dump()'s inner workings (a relief to me, at least), and it also demonstrates that it's the reference count that matters, not the "temporary-ness" of the original data storage.

所以。我提出以下主张:在PHP中,为call_user_func_array(的目的)(可能更多),说一个数据项是引用是同样的事情的话称,该项目的引用计数大于或等于2 (忽略PHP的内存优化为等值的标量)

So. I make the following assertion: In PHP, for the purpose of call_user_func_array() (and probably more), saying that a data item is a "reference" is the same thing as saying that the item's reference count is greater than or equal to 2 (ignoring PHP's internal memory optimizations for equal-valued scalars)

文案注:我很想给马里奥网站信用的答案,因为他是第一个提出正确的答案,但因为他在评论中写道它,而不是一个实际的答案,我不能这样做它: - (

Administrivia note: I'd love to give mario the site credit for the answer, as he was the first to suggest the correct answer, but since he wrote it in a comment, not an actual answer, I couldn't do it :-(

推荐答案

传递数组作为参考:

  function setArray(&$vals) {
    foreach ($vals as $key => &$value) {
      $this->myarray[] =& $value;
    }
    $this->dumpArray();
  }

我的猜测(这可能是错误的一些细节,但希望正确的大部分),为什么这使得按照预期的code的工作就是当你传递作为一种价值,一切都很酷呼叫到 dumpArray()里面的 setArray(),因为参照 $瓦尔斯 setArray阵列()仍然存在。但是,当控制返回到 MYFUNC()那么该临时变量作为是它的所有引用了。所以PHP解除分配内存之前,尽职尽责地改变了数组的字符串值,而不是引用。但是,如果你把它作为从参考 MYFUNC()然后 setArray()使用引用到生活的数组就当控制返回到 MYFUNC()

My guess (which could be wrong in some details, but is hopefully correct for the most part) as to why this makes your code work as expected is that when you pass as a value, everything's cool for the call to dumpArray() inside of setArray() because the reference to the $vals array inside setArray() still exist. But when control returns to myfunc() then that temporary variable is gone as are all references to it. So PHP dutifully changes the array to string values instead of references before deallocating the memory for it. But if you pass it as a reference from myfunc() then setArray() is using references to an array that lives on when control returns to myfunc().

这篇关于我的PHP引用数组"神奇"成为值的数组...为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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