TL; DR
a) метод / функция читает только аргумент массива => неявная (внутренняя) ссылка
б) метод / функция изменяет аргумент массива => значение
c) аргумент массива метода / функции явно помечается как ссылка (с амперсандом) => явная (пользовательская) ссылка
Или это:
- параметр массива без амперсанда : передается по ссылке; операции записи изменяют новую копию массива, копия которой создается при первой записи;
- параметр массива амперсанд : передается по ссылке; Операции записи изменяют исходный массив.
Помните - PHP делает копию значения в тот момент, когда вы пишете в параметре массива без амперсанда. Вот что означает copy-on-write
. Я бы хотел показать вам источник C этого поведения, но там страшно. Лучше использовать xdebug_debug_zval () .
Паскаль МАРТИН был прав. Коста Контос был еще больше.
Ответ
Это зависит.
Длинная версия
Я думаю, что записываю это для себя. У меня должен быть блог или что-то ...
Всякий раз, когда люди говорят о ссылках (или указателях, если на то пошло), они обычно заканчивают логотипом (просто посмотрите на эту ветку !).
PHP был почтенным языком, и я подумал, что должен допустить путаницу (даже если это резюме приведенных выше ответов). Потому что, хотя два человека могут быть правы одновременно, вам лучше просто разбить им головы в один ответ.
Прежде всего, вы должны знать, что вы не педант, если не отвечаете черно-белым способом . Все сложнее, чем «да / нет».
Как вы увидите, вся вещь по значению / по ссылке очень сильно связана с тем, что именно вы делаете с этим массивом в области действия вашего метода / функции: его чтение или изменение?
Что говорит PHP? (он же "изменится")
В руководстве сказано следующее (выделено мной):
По умолчанию аргументы функции передаются по значению (так что если
значение аргумента внутри функции изменено , не получается
изменилось за пределами функции). Чтобы разрешить функции изменить ее
аргументы, они должны быть переданы по ссылке .
Чтобы аргументировать
функция всегда передается по ссылке, добавьте амперсанд (&) к
имя аргумента в определении функции
Насколько я могу судить, когда большие, серьезные, честные программисты говорят о ссылках, они обычно говорят о изменении значения этой ссылки . И это именно то, о чем говорится в руководстве: hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
.
Однако есть еще один случай, о котором они не упоминают: что, если я ничего не изменю - просто читаю?
Что если вы передадите массив методу, который явно не помечает ссылку, и мы не изменим этот массив в области действия функции? E.g.:
<?php
function readAndDoStuffWithAnArray($array)
{
return $array[0] + $array[1] + $array[2];
}
$x = array(1, 2, 3);
echo readAndDoStuffWithAnArray($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 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);
Ну, а теперь, если бы это было на самом деле передачей по значению, у нас бы ушло около 3 МБ + ОЗУ, потому что есть две копии этого массива, верно?
Неправильно. Пока мы не меняем переменную $arr
, это ссылка в отношении памяти . Вы просто не видите этого. Вот почему PHP упоминает user-land ссылки , когда речь идет о &$someVar
, чтобы различать внутренние и явные (с амперсандом).
Факты
Итак, when an array is passed as an argument to a method or function is it passed by reference?
Я придумал три (да, три) дела:
а) метод / функция читает только аргумент массива
б) метод / функция изменяет аргумент массива
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
.
в) аргумент массива метода / функции явно помечается как ссылка (с амперсандом)
Теперь давайте посмотрим, сколько памяти занимает операция записи в явную ссылку (запустите здесь ) - обратите внимание на амперсанд в сигнатуре функции:
<?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! Таким образом, это потребляет примерно столько же памяти, сколько при чтении из параметра без амперсанда .