当一个数组作为参数传递给方法或函数时,它是通过引用传递的吗?
这样做:
$a = array(1,2,3);
$b = $a;
$b
是$a
的引用吗?
答案 0 :(得分:246)
对于问题的第二部分,请参阅array page of the manual,其中说明(引用):
数组赋值总是涉及值 复制。使用引用运算符 通过引用复制数组。
以下给出的例子:
<?php
$arr1 = array(2, 3);
$arr2 = $arr1;
$arr2[] = 4; // $arr2 is changed,
// $arr1 is still array(2, 3)
$arr3 = &$arr1;
$arr3[] = 4; // now $arr1 and $arr3 are the same
?>
对于第一部分,最好的方法是尝试; - )
考虑这个代码示例:
function my_func($a) {
$a[] = 30;
}
$arr = array(10, 20);
my_func($arr);
var_dump($arr);
它会给出这个输出:
array
0 => int 10
1 => int 20
这表明该函数没有修改作为参数传递的“外部”数组:它作为副本传递,而不是引用。
如果您希望通过引用传递,则必须以这种方式修改函数:
function my_func(& $a) {
$a[] = 30;
}
输出将变为:
array
0 => int 10
1 => int 20
2 => int 30
这次,数组已经“通过引用”传递。
不要犹豫,阅读手册的References Explained部分:它应该回答您的一些问题; - )
答案 1 :(得分:103)
关于你的第一个问题,数组是通过引用传递的,除非它在你调用的方法/函数中被修改。如果您尝试在方法/函数中修改数组,则首先创建它的副本,然后仅修改副本。这使得它看起来好像数组是按值传递的,而实际上并非如此。
例如,在第一种情况下,即使您没有通过引用定义函数来接受$ my_array(通过使用参数定义中的&amp;字符),它仍然通过引用传递(即:你不要用不必要的副本浪费内存。
function handle_array($my_array) {
// ... read from but do not modify $my_array
print_r($my_array);
// ... $my_array effectively passed by reference since no copy is made
}
但是,如果修改数组,首先会复制它(使用更多内存但不会影响原始数组)。
function handle_array($my_array) {
// ... modify $my_array
$my_array[] = "New value";
// ... $my_array effectively passed by value since requires local copy
}
仅供参考 - 这被称为“懒惰副本”或“写时复制”。
答案 2 :(得分:69)
a)方法/函数仅读取数组参数=&gt; 隐含(内部)引用
b)方法/函数修改数组参数=&gt;的值强>
c)方法/函数数组参数被明确标记为引用(带有&符号)=&gt; 显式(用户土地)参考
或者这个:
- 非&符号数组参数:通过引用传递;写入操作改变了数组的新副本,在第一次写入时创建的副本;
- &符号数组参数:通过引用传递;写入操作改变了原始数组。
记住 - 当你将写入非&符号数组参数时,PHP会对进行值复制。 copy-on-write
的意思是什么。我很乐意向你展示这种行为的C源,但它在那里很可怕。更好地使用xdebug_debug_zval()。
取决于。
我想我是为自己写的。我应该有一个博客或其他东西......
每当人们谈论引用(或指针,就此而言)时,他们通常会陷入一种不合时宜的状态(只需看看thread!)。 PHP是一种古老的语言,我认为我应该加入混乱(尽管这是对上述答案的总结)。因为,虽然两个人可以在同一时间做对,但你最好只是将他们的头脑合在一起作为一个答案。
首先,如果你不以黑白方式回答,你应该知道你不是一个迂腐的人。事情比#34;是/否&#34;更复杂。
正如您将看到的那样,整个按值/按引用的内容与您在方法/函数范围内对该数组的确切做法非常相关:读取或修改它?
manual说明了这一点(强调我的):
默认情况下,函数参数是按值传递(所以如果是 函数中的参数值为已更改,但未获取 在功能之外改变了)。允许函数修改 参数,它们必须通过引用传递。
要有一个参数 函数总是通过引用传递,在&符号前加上&符号 函数定义中的参数名称
据我所知,当大,严肃,诚实的上帝程序员谈论引用时,他们通常会谈论改变该引用的价值。这正是手册所说的:hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
。
还有一个他们没有提及的案例:如果我什么都不做改变怎么办 - 只需阅读?
如果将数组传递给没有明确标记引用的方法,并且我们不在函数范围内更改该数组,该怎么办?又名:
<?php
function printArray($array) {}
$x = array(1);
printArray($x);
请继续阅读,我的同路人。
同样严肃认真的程序员,当他们变得更加严肃时,他们会谈论内存优化&#34;关于参考。 PHP也是如此。因为PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting
,why。
将HUGE数组传递给各种函数并不是理想的,而PHP则需要复制它们(这就是&#34;传值和#34;毕竟) :
<?php
// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from you RAM
$x = array_fill(0, 10000, 1);
// pass by value, right? RIGHT?
function readArray($arr) { // <-- a new symbol (variable) gets created here
echo count($arr); // let's just read the array
}
readArray($x);
现在好了,如果这实际上是按值传递,我们就会有3mb + RAM消失,因为该数组有两个副本,对吧?
错误。只要我们不更改$arr
变量,那就是记忆。你只是没有看到它。这就是为什么PHP mentions user-land 引用来讨论&$someVar
,以区分内部和外部(带&符号)的内容。
所以,when an array is passed as an argument to a method or function is it passed by reference?
我提出了三(是的,三个)案件:
a)方法/函数仅读取数组参数
b)方法/函数修改数组参数
c)方法/函数数组参数明确标记为引用(带符号)
首先,让我们看一下数组实际吃多少内存(运行here):
<?php
$start_memory = memory_get_usage();
$x = array_fill(0, 10000, 1);
echo memory_get_usage() - $start_memory; // 1331840
那么多字节。大。
现在让我们创建一个只读取所述数组作为参数的函数,我们将看到读取逻辑需要多少内存:
<?php
function printUsedMemory($arr)
{
$start_memory = memory_get_usage();
count($arr); // read
$x = $arr[0]; // read (+ minor assignment)
$arr[0] - $arr[1]; // read
echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}
$x = array_fill(0, 10000, 1); // this is 1331840 bytes
printUsedMemory($x);
想猜?我80岁了! See for yourself。这是PHP手册省略的部分。如果$arr
param实际上是按值传递的,那么您会看到与1331840
字节类似的内容。似乎$arr
表现得像一个参考,不是吗?这是因为 是一个引用 - 一个内部引用。
现在,让写到该参数,而不是从中读取:
<?php
function printUsedMemory($arr)
{
$start_memory = memory_get_usage();
$arr[0] = 1; // WRITE!
echo memory_get_usage() - $start_memory; // let's see the memory used whilst reading
}
$x = array_fill(0, 10000, 1);
printUsedMemory($x);
再次,see for yourself,但是,对我来说,这非常接近1331840.所以在这种情况下,数组 实际上被复制到{{1} }。
现在让我们看看对显式引用的写操作需要多少内存(运行here) - 注意函数签名中的&符号:
$arr
我敢打赌你最多可以获得200分!因此,这比从非&符号读取读取的内存大致相同。
答案 3 :(得分:11)
默认
对象数组按值(数组)传递,但每个对象都通过引用传递。
<?php
$obj=new stdClass();
$obj->field='world';
$original=array($obj);
function example($hello) {
$hello[0]->field='mundo'; // change will be applied in $original
$hello[1]=new stdClass(); // change will not be applied in $original
$
}
example($original);
var_dump($original);
// array(1) { [0]=> object(stdClass)#1 (1) { ["field"]=> string(5) "mundo" } }
注意:作为优化,每个值都作为引用传递,直到在函数内部进行修改。如果它被修改并且值通过引用传递,那么它将被复制并修改副本。
答案 4 :(得分:4)
当一个数组传递给PHP中的方法或函数时,它会按值传递,除非你通过引用显式传递它,如下所示:
function test(&$array) {
$array['new'] = 'hey';
}
$a = $array(1,2,3);
// prints [0=>1,1=>2,2=>3]
var_dump($a);
test($a);
// prints [0=>1,1=>2,2=>3,'new'=>'hey']
var_dump($a);
在第二个问题中,$b
不是$a
的引用,而是$a
的副本。
与第一个示例非常相似,您可以通过执行以下操作来引用$a
:
$a = array(1,2,3);
$b = &$a;
// prints [0=>1,1=>2,2=>3]
var_dump($b);
$b['new'] = 'hey';
// prints [0=>1,1=>2,2=>3,'new'=>'hey']
var_dump($a);
答案 5 :(得分:1)
这个帖子有点老了但是我遇到过这样的事情:
试试这段代码:
$date = new DateTime();
$arr = ['date' => $date];
echo $date->format('Ymd') . '<br>';
mytest($arr);
echo $date->format('Ymd') . '<br>';
function mytest($params = []) {
if (isset($params['date'])) {
$params['date']->add(new DateInterval('P1D'));
}
}
http://codepad.viper-7.com/gwPYMw
请注意,$ params参数没有放大器,但仍会更改$ arr [&#39; date&#39;]的值。这与这里的所有其他解释和我迄今为止的想法并不完全匹配。
如果我克隆$ params [&#39; date&#39;]对象,则第二个输出日期保持不变。如果我只是将它设置为一个字符串,它也不会影响输出。
答案 6 :(得分:0)
在PHP中,默认情况下,数组会按值传递给函数,除非您通过引用显式传递它们,如下面的代码段所示:
$foo = array(11, 22, 33);
function hello($fooarg) {
$fooarg[0] = 99;
}
function world(&$fooarg) {
$fooarg[0] = 66;
}
hello($foo);
var_dump($foo); // (original array not modified) array passed-by-value
world($foo);
var_dump($foo); // (original array modified) array passed-by-reference
这是输出:
array(3) {
[0]=>
int(11)
[1]=>
int(22)
[2]=>
int(33)
}
array(3) {
[0]=>
int(66)
[1]=>
int(22)
[2]=>
int(33)
}
答案 7 :(得分:0)
为扩展答案之一,多维数组的子数组也将按值传递,除非通过引用显式传递。
<?php
$foo = array( array(1,2,3), 22, 33);
function hello($fooarg) {
$fooarg[0][0] = 99;
}
function world(&$fooarg) {
$fooarg[0][0] = 66;
}
hello($foo);
var_dump($foo); // (original array not modified) array passed-by-value
world($foo);
var_dump($foo); // (original array modified) array passed-by-reference
结果是:
array(3) {
[0]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
[1]=>
int(22)
[2]=>
int(33)
}
array(3) {
[0]=>
array(3) {
[0]=>
int(66)
[1]=>
int(2)
[2]=>
int(3)
}
[1]=>
int(22)
[2]=>
int(33)
}