1)当数组作为参数传递给方法或函数时,它是按引用传递还是按值传递?
2)将数组分配给变量时,新变量是对原始数组的引用,还是新副本?
怎么办呢:
$a = array(1,2,3);
$b = $a;
是$b
参考$a
吗?
1)当数组作为参数传递给方法或函数时,它是按引用传递还是按值传递?
2)将数组分配给变量时,新变量是对原始数组的引用,还是新副本?
怎么办呢:
$a = array(1,2,3);
$b = $a;
是$b
参考$a
吗?
Answers:
对于问题的第二部分,请参见手册的数组页面,其中指出(引用):
数组分配始终涉及值复制。使用引用运算符通过引用复制数组。
并给出示例:
<?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
同样,这次,该数组已“通过引用”传递。
不要犹豫,阅读手册的“ 参考说明”部分:它应该回答您的一些问题;-)
&
,是的,它应该-看到php.net/manual/en/...
关于第一个问题,除非您在要调用的方法/函数中对其进行了修改,否则数组将通过引用传递。如果您尝试在方法/函数中修改数组,则先创建其副本,然后再修改该副本。这使得好像数组实际上是通过值传递的,而实际上不是。
例如,在第一种情况下,即使您没有将函数定义为通过引用接受$ my_array(通过在参数定义中使用&字符),它仍会通过引用传递(即:您不会浪费内存)并附上不必要的副本)。
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
}
仅供参考-这就是所谓的“惰性复制”或“写时复制”。
a)方法/函数仅读取数组参数=> 隐式(内部)引用
b)方法/函数修改数组参数=> 值
c)方法/函数数组参数被显式标记为引用(与号) => 明确的(用户区域)引用
或这样:
- 非&数组参数:通过引用传递;写入操作会更改阵列的新副本,即在第一次写入时创建的副本;
-与符号数组参数:通过引用传递;写入操作会更改原始数组。
请记住- 当您写入非符号数组参数时,PHP会进行值复制。那是什么copy-on-write
意思 我很想向您展示此行为的C源代码,但是其中的内容令人恐惧。最好使用xdebug_debug_zval()。
Pascal MARTIN是对的。Kosta Kontos更是如此。
这取决于。
我想我正在为自己写下这些。我应该有一个博客之类的东西。
每当人们谈论引用(或指针)时,它们通常都会以通俗的形式出现(只需看一下该线程!)。
PHP是一种古老的语言,我认为我应该加倍混淆(即使这是上述答案的总结)。因为,尽管两个人可能同时是对的,但最好还是将他们的头脑拼凑成一个答案。
首先,如果您不以黑白方式回答,您应该知道自己不是学徒。事情比“是/否”要复杂得多。
就像您将看到的那样,整个按值/按引用的事情与您在方法/函数范围内对该数组的确切用途有很大关系:读取还是修改它?
该手册说,这(重点煤矿):
默认情况下,函数参数是按值传递的(因此,如果函数中参数的值发生更改,则不会在函数外部进行更改)。要允许函数修改其参数,必须通过reference传递它们。
要使函数的参数始终通过引用传递,请在函数定义中的参数名称前加上“&”号
据我所知,当大型,认真,诚实的程序员谈论引用时,他们通常谈论的是改变引用的价值。而这正是手册所讨论的内容:hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
。
不过,还有另一种情况他们没有提到:如果我什么都没改变-只是阅读怎么办?
如果将数组传递给未显式标记引用的方法,而我们又不在函数范围内更改该数组怎么办?例如:
<?php
function readAndDoStuffWithAnArray($array)
{
return $array[0] + $array[1] + $array[2];
}
$x = array(1, 2, 3);
echo readAndDoStuffWithAnArray($x);
继续阅读,我的旅行者。
同样重要的大型程序员,当他们变得更加认真时,他们会在引用方面谈论“内存优化”。PHP也是如此。因为PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting
,这就是原因。
将HUGE数组传递给各种函数和PHP来复制它们不是理想的(毕竟,“按值传递”就是这样做的):
<?php
// filling an array with 10000 elements of int 1
// let's say it grabs 3 mb from your 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 在谈论时会提及 用户区域引用&$someVar
,以区分内部和显式(带有&符)的原因。
所以, when an array is passed as an argument to a method or function is it passed by reference?
我提出了三种(是,三种)情况:
a)方法/函数只读取数组参数
b)方法/函数修改数组参数
c)方法/函数数组参数被明确标记为引用(带有连字号)
首先,让我们看看该数组实际消耗了多少内存(在此处运行):
<?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!自己看看。这是PHP手册省略的部分。如果$arr
参数实际上是按值传递的,则将看到类似于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);
再次,看到自己,但对我来说,那是相当接近在这种情况下是1331840.因此,该阵列是实际上被复制到$arr
。
现在让我们看一下对一个显式引用的写操作需要多少内存(在此处运行)-注意函数签名中的“&”号:
<?php
function printUsedMemory(&$arr) // <----- explicit, user-land, pass-by-reference
{
$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);
我敢打赌,您的最高筹码为200!因此,这消耗的内存与从非“&”参数读取的内存差不多。
默认
对象数组按值(数组)传递,但每个对象均按引用传递。
<?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" } }
注意:作为优化,将每个值作为引用传递,直到在函数内部对其进行修改为止。如果对其进行了修改并且该值是通过引用传递的,则将其复制并修改副本。
当数组传递给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);
这个线程有点旧,但是在这里我碰到了一些东西:
试试这个代码:
$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 ['date']的值。这与这里的所有其他解释以及我到目前为止的想法均不完全一致。
如果我克隆$ params ['date']对象,则第二个输出日期保持不变。如果我只是将其设置为字符串,则也不会影响输出。
为了扩展答案之一,多维数组的子数组也将按值传递,除非通过引用显式传递。
<?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)
}
在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)
}