Массивы в PHP передаются по значению или по ссылке?
когда массив передается в качестве аргумента в метод или функцию он передается по ссылке?
насчет этого:
$a = array(1,2,3);
$b = $a;
Is $b
ссылка $a
?
7 ответов
для второй части вашего вопроса см. страница массива руководства указано, что (цитирую) :
назначение массива всегда включает стоимость копирование. Используйте справочник оператора скопируйте массив по ссылке.
и приведенный пример :
<?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
}
FYI-это известно как" ленивая копия "или"копирование при записи".
TL; DR
a) метод/функция только чтение аргумент Array => неявные (внутренние) ссылки
б) метод/функция изменение аргумент Array => стоимостью
c) аргумент массива метода/функции явно помечен как ссылка (с амперсандом)=>явная (пользовательская) ссылка
или такой:
- массив без амперсанда парам!--20-->: передается по ссылке; операции записи изменяют новую копию массива, копия которого создается при первой записи;
- амперсанд array param: передается по ссылке; операции записи изменяют исходный массив.
помните-PHP делает значение-copy тот момент, когда вы пишите не амперсанд массив парам. Вот что!--6--> средства. Я бы хотел показать вам источник этого поведения, но там страшно. Лучше использовать xdebug_debug_zval ().
ответ
это зависит.
текст
кажется, я записываю это для себя. Мне нужен блог или что-то в этом роде...
всякий раз, когда люди говорят о ссылках (или указателях, если на то пошло), они обычно заканчиваются логомахией (просто посмотрите на это нить!).
PHP является почтенный язык, я думал, что должен добавить к путанице (хотя это резюме вышеуказанных ответов). Потому что, хотя два человека могут быть правы одновременно, вам лучше просто разбить их головы в один ответ.
во-первых, вы должны знать, что вы не педант, если не отвечаете в черно-белой манере. Все сложнее, чем"да/нет".
как вы увидите, все по значению / по ссылке вещь очень связана с тем, что именно вы делаете с этим массивом в своей области метода/функции: читаете его или модифицируете?
что говорит PHP? (он же "перемены")
на руководство говорит это (Курсив мой):
по умолчанию аргументы в функцию передан по значению (так что если значение аргумента в функции -изменить, он не получает измененный вне функция.) Чтобы разрешить функции изменить its аргументы, они должны быть прошел по ссылке.
чтобы иметь аргумент функция, всегда передаваемая по ссылке, добавляет амперсанд ( & ) к имя аргумента в определении функции
насколько я могу судить, когда большие, серьезные, честные программисты говорят о ссылках, они обычно говорят о изменение значения этой ссылки. И именно об этом говорится в руководстве:hey, if you want to CHANGE the value in a function, consider that PHP's doing "pass-by-value"
.
есть еще один случай, о котором они не упоминают: что, если я ничего не изменю - просто прочитаю?
Что делать, если вы передадите массив методу, который явно не помечает ссылку, и мы не изменим этот массив в области функции? Aka:
<?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-делать их копии (в конце концов, это то, что делает" pass-by-value"):
<?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);
Ну, если бы это действительно было pass-by-value, у нас было бы немного 3MB+ RAM, потому что есть два копии этого массив, верно?
неправильно. Пока мы не изменим $arr
переменная, это ссылка,памяти-мудрый. Ты просто не видишь этого. Вот почему PHP упоминает пользователей-земли ссылки говоря о &$someVar
, чтобы различать внутренние и явные (с амперсандом).
факты
и when an array is passed as an argument to a method or function is it passed by reference?
я придумал три (да, три) случаи:
а) метод/функция только чтение аргумент массив
б) метод/функция изменение аргумент массив
c) аргумент массива метода/функции явно помечен как ссылка (с амперсандом)
во-первых, давайте посмотрим, сколько памяти этот массив на самом деле ест (run здесь):
<?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
ведет себя как ссылка, не так ли? Потому что это is a references - внутренний.
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. Итак, в этом случае массив is на самом деле копируется в $arr
.
c) аргумент массива метод / функция явно помечен как ссылка (с амперсандом)
теперь давайте посмотрим, сколько операция записи в явную ссылку принимает (run здесь) - обратите внимание на амперсанд в подписи функции:
<?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 максимум! Таким образом, это съедает примерно столько же памяти, сколько чтение из не амперсанд парам.
по умолчанию
- примитивы передаются по значению. Вряд ли 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" } }
Примечание: в качестве оптимизации каждое значение передается в качестве ссылки до его изменения внутри функции. Если он изменен и значение было передано по ссылке, то он копируется и копия изменяется.
когда массив передается методу или функции в 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(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)
}