PHP 中的数组在传递给函数时是否作为值或对新变量的引用进行复制?
1)当数组作为参数传递给方法或函数时,它是按引用传递还是按值传递?
2) 将数组赋值给变量时,新变量是对原始数组的引用,还是新的副本?
这样做怎么样:
$a = array(1,2,3);
$b = $a;
$b
是对 $a
的引用吗?
1) When an array is passed as an argument to a method or function, is it passed by reference, or by value?
2) When assigning an array to a variable, is the new variable a reference to the original array, or is it new copy?
What about doing this:
$a = array(1,2,3);
$b = $a;
Is $b
a reference to $a
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
对于问题的第二部分,请参阅手册的数组页面 ,其中指出(引用):
以及给定的示例:
对于第一部分,最好的方法是尝试;-)
考虑这个代码示例:
它将给出以下输出:
这表明该函数尚未修改作为参数传递的“外部”数组:它是作为副本传递,而不是参考。
如果您希望它通过引用传递,则必须修改该函数,如下所示:
输出将变为:
因为,这一次,数组已“通过引用”传递。
不要犹豫,阅读手册的参考解释部分:它应该回答你的一些问题;-)
For the second part of your question, see the array page of the manual, which states (quoting) :
And the given example :
For the first part, the best way to be sure is to try ;-)
Consider this example of code :
It'll give this output :
Which indicates the function has not modified the "outside" array that was passed as a parameter : it's passed as a copy, and not a reference.
If you want it passed by reference, you'll have to modify the function, this way :
And the output will become :
As, this time, the array has been passed "by reference".
Don't hesitate to read the References Explained section of the manual : it should answer some of your questions ;-)
关于您的第一个问题,数组是通过引用传递的,除非它在您调用的方法/函数中进行了修改。如果您尝试在方法/函数中修改数组,则会首先创建它的副本,然后仅修改该副本。这使得数组看起来好像是按值传递的,但实际上并非如此。
例如,在第一种情况下,即使您没有将函数定义为通过引用接受 $my_array (通过在参数定义中使用 & 字符),它仍然通过引用传递(即:您不会浪费内存中存在不必要的副本)。
但是,如果您修改数组,则会首先创建它的副本(这会使用更多内存,但不会影响原始数组)。
仅供参考 - 这称为“惰性复制”或“写时复制”。
With regards to your first question, the array is passed by reference UNLESS it is modified within the method / function you're calling. If you attempt to modify the array within the method / function, a copy of it is made first, and then only the copy is modified. This makes it seem as if the array is passed by value when in actual fact it isn't.
For example, in this first case, even though you aren't defining your function to accept $my_array by reference (by using the & character in the parameter definition), it still gets passed by reference (ie: you don't waste memory with an unnecessary copy).
However if you modify the array, a copy of it is made first (which uses more memory but leaves your original array unaffected).
FYI - this is known as "lazy copy" or "copy-on-write".
TL;DR
a) 方法/函数仅读取数组参数 => 隐式(内部)引用
b) 方法/函数修改数组参数 => 价值
c) 方法/函数数组参数被显式标记为引用(带有 & 符号)=> 显式(用户态)参考
或者这样:
- 非&符号数组参数:通过引用传递;写入操作会更改数组的新副本,该副本是在第一次写入时创建的;
- & 符号数组参数:通过引用传递;写入操作会改变原始数组。
请记住 - PHP 在您写入非&符号数组参数时执行值复制。这就是
copy-on-write
的意思。我很想向您展示这种行为的 C 源代码,但其中很可怕。最好使用xdebug_debug_zval()。帕斯卡·马丁是对的。科斯塔·康托斯更是如此。
回答
这取决于。
长版本
我想我正在为自己写下这篇文章。我应该有一个博客或其他东西......
每当人们谈论参考文献(或指针,就此而言)时,他们通常都会以徽标学结束(只需看看这个 线程!)。
PHP 是一种古老的语言,我认为我应该增加混乱(尽管这是上述答案的总结)。因为,尽管两个人可能同时是正确的,但你最好还是将他们的头脑集中在一起得出一个答案。
首先,你应该知道,如果你不以黑白分明的方式回答,你就不是一个学究。事情比“是/否”更复杂。
正如您将看到的,整个按值/按引用的事情与您在方法/函数作用域中对该数组执行的操作非常相关:读取它还是修改它?
PHP 说什么? (又名“change-wise”)
手册< /a> 说的是(强调我的):
据我所知,当大的、严肃的、诚实的程序员谈论引用时,他们通常会谈论改变该引用的值。这正是手册所讨论的内容:
嘿,如果您想更改函数中的值,请考虑 PHP 正在执行“按值传递”
。不过,还有另一种情况他们没有提到:如果我不改变任何东西怎么办 - 只是阅读?
如果将数组传递给未显式标记引用的方法,并且我们不在函数作用域中更改该数组,该怎么办?例如:
请继续阅读,我的旅伴。
PHP 实际上是做什么的? (又名“内存优化”)
同样的大而严肃的程序员,当他们变得更加严肃时,他们谈论关于引用的“内存优化”。 PHP 也是如此。因为 PHP 是一种动态的、松散类型的语言,它使用写时复制和引用计数,所以这就是 为什么。
将巨大的数组传递给各种函数以及 PHP 来复制它们(毕竟这就是“按值传递”的作用)并不理想:
现在,如果这实际上是按值传递,我们会失去一些 3mb+ RAM,因为该数组有两个副本,对吧?
错误的。只要我们不更改
$arr
变量,它就是一个内存方面的引用。你只是看不到而已。这就是 PHP 提及用户的原因-land 在谈论&$someVar
时引用,以区分内部和显式(带有&符号)。事实
那么,
当数组作为参数传递给方法或函数时,它是通过引用传递的吗?
我想出了三个(是的,三个)情况:
a) 方法/函数仅读取数组参数
b) 方法/函数修改数组参数
c) 方法/函数数组参数被显式标记为引用(使用 & 符号)
首先,让我们看看该数组实际占用了多少内存(运行 此处):
那么多字节。伟大的。
a) 方法/函数仅读取数组参数
现在让我们创建一个仅读取所述数组作为参数的函数,我们将看到读取逻辑有多少内存需要:
想猜吗?我得80分! 亲自看看。这是 PHP 手册省略的部分。如果
$arr
参数实际上是按值传递的,您会看到类似于1331840
字节的内容。看起来$arr
的行为就像一个引用,不是吗?那是因为它是一个引用 - 一个内部引用。b) 方法/函数修改数组参数
现在,让我们写入该参数,而不是从中读取:
再次,亲自看看,但是,对我来说,这非常接近 1331840。所以在这种情况下,数组实际上被复制到
$arr
。c) 方法/函数数组参数被显式标记为引用(使用 & 符号)
现在让我们看看对显式引用的写入操作需要多少内存(运行 此处) - 请注意函数签名中的 & 符号:
我打赌您最多会得到 200!因此,这消耗的内存大约与从非&符号参数读取一样多。
TL;DR
a) the method/function only reads the array argument => implicit (internal) reference
b) the method/function modifies the array argument => value
c) the method/function array argument is explicitly marked as a reference (with an ampersand) => explicit (user-land) reference
Or this:
- non-ampersand array param: passed by reference; the writing operations alter a new copy of the array, copy which is created on the first write;
- ampersand array param: passed by reference; the writing operations alter the original array.
Remember - PHP does a value-copy the moment you write to the non-ampersand array param. That's what
copy-on-write
means. I'd love to show you the C source of this behaviour, but it's scary in there. Better use xdebug_debug_zval().Pascal MARTIN was right. Kosta Kontos was even more so.
Answer
It depends.
Long version
I think I'm writing this down for myself. I should have a blog or something...
Whenever people talk of references (or pointers, for that matter), they usually end up in a logomachy (just look at this thread!).
PHP being a venerable language, I thought I should add up to the confusion (even though this a summary of the above answers). Because, although two people can be right at the same time, you're better off just cracking their heads together into one answer.
First off, you should know that you're not a pedant if you don't answer in a black-and-white manner. Things are more complicated than "yes/no".
As you will see, the whole by-value/by-reference thing is very much related to what exactly are you doing with that array in your method/function scope: reading it or modifying it?
What does PHP says? (aka "change-wise")
The manual says this (emphasis mine):
As far as I can tell, when big, serious, honest-to-God programmers talk about references, they usually talk about altering the value of that reference. And that's exactly what the manual talks about:
hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
.There's another case that they don't mention, though: what if I don't change anything - just read?
What if you pass an array to a method which doesn't explicitly marks a reference, and we don't change that array in the function scope? E.g.:
Read on, my fellow traveller.
What does PHP actually do? (aka "memory-wise")
The same big and serious programmers, when they get even more serious, they talk about "memory optimizations" in regards to references. So does PHP. Because
PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting
, that's why.It wouldn't be ideal to pass HUGE arrays to various functions, and PHP to make copies of them (that's what "pass-by-value" does, after all):
Well now, if this actually was pass-by-value, we'd have some 3mb+ RAM gone, because there are two copies of that array, right?
Wrong. As long as we don't change the
$arr
variable, that's a reference, memory-wise. You just don't see it. That's why PHP mentions user-land references when talking about&$someVar
, to distinguish between internal and explicit (with ampersand) ones.Facts
So,
when an array is passed as an argument to a method or function is it passed by reference?
I came up with three (yeah, three) cases:
a) the method/function only reads the array argument
b) the method/function modifies the array argument
c) the method/function array argument is explicitly marked as a reference (with an ampersand)
Firstly, let's see how much memory that array actually eats (run here):
That many bytes. Great.
a) the method/function only reads the array argument
Now let's make a function which only reads the said array as an argument and we'll see how much memory the reading logic takes:
Wanna guess? I get 80! See for yourself. This is the part that the PHP manual omits. If the
$arr
param was actually passed-by-value, you'd see something similar to1331840
bytes. It seems that$arr
behaves like a reference, doesn't it? That's because it is a references - an internal one.b) the method/function modifies the array argument
Now, let's write to that param, instead of reading from it:
Again, see for yourself, but, for me, that's pretty close to being 1331840. So in this case, the array is actually being copied to
$arr
.c) the method/function array argument is explicitly marked as a reference (with an ampersand)
Now let's see how much memory a write operation to an explicit reference takes (run here) - note the ampersand in the function signature:
My bet is that you get 200 max! So this eats approximately as much memory as reading from a non-ampersand param.
默认情况下,
对象数组通过值(数组)传递,但每个对象都是通过引用传递。
<前><代码>field='world';
$原始=数组($obj);
函数示例($hello) {
$hello[0]->field='mundo'; // 更改将应用于 $original
$hello[1]=new stdClass(); // 更改不会应用于 $original
$
}
示例($原始);
var_dump($原始);
// 数组(1) { [0]=>;对象(stdClass)#1 (1) { ["field"]=>字符串(5)“世界”}}
注意:作为优化,每个值都作为引用传递,直到在函数内修改为止。如果它被修改并且值是通过引用传递的,那么它会被复制并修改副本。
By default
Arrays of objects are passed by value (the array) but each object is passed by reference.
Note: As an optimization, every single value is passed as reference until its modified inside the function. If it's modified and the value was passed by reference then, it's copied and the copy is modified.
当数组传递给 PHP 中的方法或函数时,它是按值传递的,除非您显式通过引用传递它,如下所示:
在第二个问题中,
$b
不是对$a
,而是$a
的副本。与第一个示例非常相似,您可以通过执行以下操作来引用
$a
:When an array is passed to a method or function in PHP, it is passed by value unless you explicitly pass it by reference, like so:
In your second question,
$b
is not a reference to$a
, but a copy of$a
.Much like the first example, you can reference
$a
by doing the following:在 PHP 中,数组默认按值传递给函数,除非您显式地按引用传递它们,如以下代码片段所示:
这是输出:
In PHP arrays are passed to functions by value by default, unless you explicitly pass them by reference, as the following snippet shows:
Here is the output:
为了扩展答案之一,多维数组的子数组也按值传递,除非通过引用显式传递。
结果是:
To extend one of the answers, also subarrays of multidimensional arrays are passed by value unless passed explicitely by reference.
The result is:
这个线程有点旧,但我刚刚遇到了一些东西:
尝试这个代码:
http://codepad.viper -7.com/gwPYMw
请注意,$params 参数没有放大器,但它仍然更改 $arr['date'] 的值。这与这里的所有其他解释以及我到目前为止的想法并不相符。
如果我克隆 $params['date'] 对象,第二个输出的日期保持不变。如果我只是将其设置为字符串,它也不会影响输出。
This thread is a bit older but here something I just came across:
Try this code:
http://codepad.viper-7.com/gwPYMw
Note there is no amp for the $params parameter and still it changes the value of $arr['date']. This doesn't really match with all the other explanations here and what I thought until now.
If I clone the $params['date'] object, the 2nd outputted date stays the same. If I just set it to a string it doesn't effect the output either.