PHP中的数组是通过值还是通过引用传递的?

当数组作为参数传递给方法或函数时,它是通过引用传递的?

那么做什么:

$a = array(1,2,3);
$b = $a;

$b的参考$a


对于问题的第二部分,请参阅手册的数组页面,其中指出(引用):

数组分配始终涉及值复制。 使用引用运算符通过引用复制数组。

举个例子:

<?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

至于这次,该数组已被“通过引用”传递。


不要犹豫,阅读手册的参考文献解释部分:它应该回答您的一些问题;-)


关于你的第一个问题,数组是通过引用传递的,除非它在你调用的方法/函数中被修改。 如果您尝试修改方法/函数中的数组,则首先创建该数组的副本,然后只修改副本。 这使得它看起来好像数组是通过值传递的,但事实上并非如此。

例如,在第一种情况下,即使您没有将函数定义为通过引用接受$ 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
}

仅供参考 - 这被称为“延迟复制”或“写入时复制”。


TL; DR

a)方法/函数只读取数组参数=> 隐式(内部)引用
b)方法/函数修改数组参数=>
c)方法/函数数组参数明确标记为引用(带&符号)=> 显式(用户区)引用

或这个:
- 非&amp;数组参数 :通过引用传递; 写入操作会修改阵列的新副本,即第一次写入时创建的副本;
- &符号数组参数 :通过引用传递; 写入操作会改变原始数组。

请记住 - 在您写入非连接数组参数的那一刻,PHP会进行值复制。 这就是copy-on-write含义。 我很乐意向你展示这种行为的C源,但它在那里很可怕。 更好地使用xdebug_debug_zval()。

帕斯卡尔马丁是正确的。 Kosta Kontos更是如此。

回答

这取决于。

长版

我想我是为自己写的。 我应该有一个博客或什么...

每当人们谈论引用(或指针,就此而言)时,它们通常会以logomachy结尾(只是看看这个线程!)。
PHP是一种古老的语言,我认为我应该加入混淆(尽管这是对上述答案的总结)。 因为,虽然两个人可以同时合适,但最好还是把他们的脑袋拼成一个答案。

首先,如果你不以黑白的方式回答,你应该知道你不是一个学问。 事情比“是/否”更复杂。

正如你将看到的那样,整个按价值/按参考值的事情与你在方法/函数范围中对该数组做什么完全相关:读取它或修改它?

PHP说什么? (又名“改变方式”)

手册说这(重点我的):

默认情况下,函数参数是按值传递的(所以如果函数中参数的值被改变 ,它不会在函数外被改变)。 要允许函数修改它的参数,它们必须通过引用传递。

要使函数的参数始终通过引用传递,请在函数定义中的参数名称前加一个&符号(&)

据我所知,当大的,严肃的,诚实的上帝程序员谈论引用时,他们通常会谈论改变引用的价值。 这正是手册所谈论的内容: 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);

请继续阅读,我的同行者。

PHP实际上做了什么? (又名“记忆明智”)

同样的大和严肃的程序员,当他们变得更加严肃时,他们会谈论关于引用的“内存优化”。 PHP也是如此。 因为PHP is a dynamic, loosely typed language, that uses copy-on-write and reference counting ,这就是原因。

把巨大的数组传递给各种函数是不理想的,而PHP将它们复制(毕竟,这就是“传值”所做的):

<?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 +内存消失,因为这个数组有两个副本,对吧?

错误。 只要我们不改变$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

那么多字节。 大。

a)方法/函数只读取数组参数

现在我们来创建一个函数,它只读取所述数组作为参数,我们将看到读取逻辑需要多少内存:

<?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行为就像一个参考,不是吗? 这是因为它一个参考 - 一个内部参考。

b)方法/函数修改数组参数

现在,让我们写下这个参数,而不是阅读它:

<?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

c)方法/函数数组参数明确标记为引用(带&符号)

现在让我们看看对显式引用的写入操作需要多少内存(在这里运行) - 注意函数签名中的和号:

<?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! 因此, 从非&amp; param参数读取的内存大约与内存相同。

链接地址: http://www.djcxy.com/p/20625.html

上一篇: Are arrays in PHP passed by value or by reference?

下一篇: Pointer does not increment, if incremented in other function