Являются ли массивы в PHP переданы по значению или по ссылке?

Когда массив передается в качестве аргумента методу или функции, он передается по ссылке?

Как это сделать:

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

Является ли $b ссылкой на $a?

230
09 янв. '10 в 0:32
источник поделиться
8 ответов

Во второй части вашего вопроса см. страницу массива руководства, в котором указывается (цитирование):

Назначение массива всегда включает значение копирование. Используйте ссылочный оператор для скопируйте массив по ссылке.

И приведенный пример:

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

Как, на этот раз, массив был передан "по ссылке".


Не стесняйтесь читать раздел Справочник по объяснению в руководстве: он должен ответить на некоторые из ваших вопросов; -)

246
09 янв. '10 в 0:34
источник

Связанные вопросы


Похожие вопросы

Что касается вашего первого вопроса, массив передается по ссылке UNLESS, он изменяется внутри метода/функции, которую вы вызываете. Если вы попытаетесь изменить массив в методе/функции, сначала будет сделана его копия, а затем будет изменена только копия. Это заставляет кажется, что массив передается по значению, когда на самом деле это не так.

Например, в этом первом случае, даже если вы не определяете свою функцию для приема $my_array по ссылке (с помощью символа и символа в определении параметра), он по-прежнему передается по ссылке (т.е. t удалять память с ненужной копией).

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
}

FYI - это называется "ленивая копия" или "копирование на запись".

103
16 марта '12 в 18:56
источник

TL; DR

a) метод/функция только читает аргумент массива = > неявная (внутренняя) ссылка
б) метод/функция изменяет аргумент массива = > значение
c) аргумент массива метода/функции явно помечен как ссылка (с амперсандом) = > явная (пользовательская) ссылка

Или это:
- массив без амперсанда: передается по ссылке; операции записи изменяют новую копию массива, копию, которая создается при первой записи;
- массив амперсанд param: передан по ссылке; операции записи изменяют исходный массив.

Помните - PHP копирует значение в момент, когда вы пишете параметр не амперсанда. То, что означает copy-on-write. Я хотел бы показать вам источник C такого поведения, но это страшно. Лучше использовать xdebug_debug_zval().

Паскаль МАРТИН был прав. Коста Контос был тем более.

Ответ

Это зависит.

Длинная версия

Думаю, я пишу это для себя. У меня должен быть блог или еще что-то...

Всякий раз, когда люди говорят о ссылках (или указателях, если на то пошло), они обычно оказываются в логомахи (просто посмотрите на этот поток!).
PHP, являющийся почтенным языком, я думал, что должен добавить в замешательство (хотя это резюме вышеупомянутых ответов). Потому что, хотя два человека могут быть правы в одно и то же время, вам лучше просто сломать головы в один ответ.

Прежде всего, вы должны знать, что вы не педант, если не отвечаете черно-белым способом. Вещи сложнее, чем "да/нет".

Как вы увидите, вся функция by-value/by-reference очень сильно связана с тем, что именно вы делаете с этим массивом в области вашего метода/функции: чтение или изменение его?

Что говорит PHP? (он же "по-разному" )

manual говорит об этом (основное внимание):

По умолчанию аргументы функции передаются по значению (так что если значение аргумента внутри функции изменено, оно не получается измененный вне функции). Чтобы разрешить функции изменить ее аргументы, они должны передаваться по ссылке.

Чтобы иметь аргумент функция всегда передается по ссылке, добавляет амперсанд (&) к имя аргумента в определении функции

Насколько я могу судить, когда большие, серьезные, честные к Богу программисты говорят о ссылках, они обычно говорят об изменении значения этой ссылки. И это то, о чем говорится в руководстве: hey, if you want to CHANGE the value in a function, consider that PHP 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, что почему.

Было бы нецелесообразно передавать HUGE массивы различным функциям, а PHP - создавать их копии (что-то вроде "pass-by-value" ):

<?php

// filling an array with 10000 elements of int 1
// let 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 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) метод/функция только читает аргумент массива
б) метод/функция изменяет аргумент массива
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 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 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 see the memory used whilst reading
}

$x = array_fill(0, 10000, 1);
printUsedMemory($x);

Моя ставка заключается в том, что вы получаете 200 макс! Таким образом, он потребляет примерно столько же памяти, сколько , считая из не амперсанда param.

69
08 апр. '14 в 17:22
источник

По умолчанию

  • Примитивы передаются по значению. Вряд ли Java, строка примитивна в PHP
  • Массивы примитивов передаются по значению
  • Объекты передаются с помощью ссылки
  • Массивы объектов передаются по значению (массив), но каждый объект передается по ссылке.

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

Примечание. В качестве оптимизации каждое отдельное значение передается как ссылка до его изменения внутри функции. Если он был изменен и значение передано по ссылке, оно копируется и копия изменяется.

11
02 апр. '16 в 13:52
источник

Когда массив передается методу или функции в 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);
4
09 янв. '10 в 0:36
источник

Этот поток немного старше, но вот что-то, с чем я только что столкнулся:

Попробуйте этот код:

$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'], вторая дата вывода останется прежней. Если я просто установил его в строку, это не повлияет на результат.

1
19 дек. '14 в 0:48
источник

В 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)
}
0
01 февр. '15 в 3:10
источник

Чтобы расширить один из ответов, также подмассивы многомерных массивов передаются по значению, если явно не переданы по ссылке.

<?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)
}
0
15 мая '19 в 2:18
источник

Посмотрите другие вопросы по меткам или Задайте вопрос