TL; DR
a) метод / функция читает только аргумент массива => неявная (внутренняя) ссылка
b) метод / функция изменяет аргумент массива => значение
c) аргумент массива метода / функции явно помечается как ссылка (с амперсандом) => явная (пользовательская) ссылка
Или это:
- параметр массива без амперсанда : передается по ссылке; операции записи изменяют новую копию массива, копия которой создается при первой записи;
- параметр массива амперсанд : передается по ссылке; Операции записи изменяют исходный массив.
Помните - PHP копирует значение в тот момент, когда вы записываете в параметр non-ampersand array. Вот что 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"
.
Однако есть еще один случай, о котором они не упоминают: что, если я ничего не изменю - просто читаю?
Что если вы передадите массив методу, который явно не помечает ссылку, и мы не изменим этот массив в области действия функции? Например:
<?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
что вот почему .
Было бы не идеальным передавать массивы 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);
Ну, а теперь, если бы это на самом деле было передачей по значению, у нас бы ушло около 3 Мб + ОЗУ, потому что есть две копии этого массива, верно?
Неправильно. Пока мы не меняем $arr
переменную, это ссылка для памяти . Вы просто не видите этого. Вот почему PHP упоминает пользователь землю ссылку , когда речь идет о &$someVar
, чтобы различать внутренние и явные (с амперсандом) из них.
факты
Так, when an array is passed as an argument to a method or function is it passed by reference?
Я придумал три (да, три) случая:
а) метод / функция читает только аргумент массива
б) метод / функция модифицирует аргумент массива
в) аргумент массива метода / функции явно помечается как ссылка (с амперсанд)
Во-первых, давайте посмотрим, сколько памяти фактически использует этот массив (запустите здесь ):
<?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
.
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 макс! Так что это съедает примерно столько же памяти, сколько и чтение из параметра без амперсанда .