php передать массив по ссылке
Массивы в PHP передаются по значению или по ссылке?
когда массив передается в качестве аргумента методу или функции передается по ссылке?
7 ответов:
назначение массива всегда включает стоимость копирование. Используйте оператор ссылки для скопируйте массив по ссылке.
рассмотрим этот пример кода :
Это даст такой выход :
что указывает на то, что функция не изменила «внешний» массив, который был передан в качестве параметра : он передается как копия, а не ссылка.
если вы хотите, чтобы он перешел по ссылке, вам придется изменить функцию, таким образом :
как, на этот раз, массив был передан » мимо ссылка.»
Не стесняйтесь читать Ссылки Объяснили раздел руководства : он должен ответить на некоторые ваши вопросы 😉
что касается вашего первого вопроса, массив передается по ссылке, если он не изменен в вызываемом методе / функции. При попытке изменить массив внутри метода / функции сначала создается его копия, а затем изменяется только копия. Это заставляет его казаться, как будто массив передается по значению, когда на самом деле это не так.
однако при изменении массива сначала создается его копия (которая использует больше памяти, но не влияет на исходный массив).
FYI-это известно как» ленивая копия «или»копирование при записи».
TL; DR
a) метод/функция только чтение аргумент Array => неявные (внутренние) ссылки
б) метод/функция изменение аргумент Array => стоимостью
c) аргумент массива метода / функции явно помечен как ссылка (с амперсандом) => явная ссылка (user-land)
или такой:
— массив без амперсанда параметр: передается по ссылке; операции записи изменяют новую копию массива, копия которой создается при первой записи;
— амперсанд массив param: передается по ссылке; операции записи изменяют исходный массив.
помните-PHP делает значение-copy в тот момент, когда вы пишете не амперсанд массив парам. Вот что copy-on-write средства. Я хотел бы показать вам Источник C такого поведения, но там страшно. Лучше используйте xdebug_debug_zval ().
Паскаль Мартин был прав. Коста Контос был еще более удивлен.
ответ
текст
я думаю, что записываю это для себя. У меня должен быть блог или что-то в этом роде.
всякий раз, когда люди говорят о ссылках (или указателях, если на то пошло), они обычно заканчивают в логомахии (просто посмотрите на это thread!).
РНР является почтенный язык, я думал, что должен добавить к путанице (хотя это резюме приведенных выше ответов). Потому что, хотя два человека могут быть правы одновременно, вам лучше просто разбить их головы вместе в один ответ.
во-первых, вы должны знать, что ты не педант, если не отвечаешь в черно-белой манере. Все гораздо сложнее, чем «да/нет».
как вы увидите, весь по значению / по ссылке это очень связано с тем, что именно вы делаете с этим массивом в своей области метода/функции: читаете его или изменяете?
что говорит PHP? (ака «изменение мудрый»)
The руководство говорит это (Курсив мой):
по умолчанию аргументы в функцию передан по значению (так что если значение аргумента внутри функции изменить, он не получает изменено за пределами функция.) Чтобы разрешить функцию изменить его аргументы, они должны быть прошел по ссылке.
чтобы иметь аргумент для a функция всегда передается по ссылке, добавьте амперсанд ( & ) к имя аргумента в определении функции
Читать далее мой попутчик.
что на самом деле делает PHP? (он же «память-мудрый»)
было бы не идеально передавать огромные массивы различным функциям, а PHP делать их копии (в конце концов, это то, что делает» pass-by-value»):
Ну теперь, если бы это действительно было pass-by-value, у нас было бы около 3 МБ+ ОЗУ, потому что есть два копии этого массив, верно?
факты
и when an array is passed as an argument to a method or function is it passed by reference?
я придумал три (да, три) случаи:
а) метод/функция только чтение аргумент массив
б) метод/функция изменение аргумент массив
c) аргумент массива метода / функции явно помечен как ссылка (с амперсандом)
во-первых, давайте посмотрим, сколько памяти этот массив на самом деле ест (run здесь):
столько байт. Отличный.
a) метод/функцию только чтение аргумент массив
теперь давайте сделаем функцию, которая только чтение указанный массив в качестве аргумента, и мы увидим, сколько памяти занимает логика чтения:
b) метод / функция изменение аргумент массив
c) аргумент массива метода / функции явно помечен как ссылка (с амперсандом)
держу пари, что вы получите 200 Макс! Так что это съедает примерно столько же памяти, как читать из-амперсанд парам.
массивы объекты передаются по значению (массив), но каждый объект передается по ссылке.
Примечание: в качестве оптимизации, каждое значение передается в качестве ссылки до его изменения внутри функции. Если он изменен и значение было передано по ссылке, то он копируется и копия изменяется.
когда массив передается методу или функции в PHP, он передается по значению, если вы явно не передаете его по ссылке, например:
этот поток немного старше, но вот что-то я только что наткнулся:
попробуйте этот код:
в PHP массивы передаются в функции по значению по умолчанию, если вы явно не передаете их по ссылке, как показано в следующем фрагменте кода:
Отрицательная сторона передачи значений по ссылкам
Без всякой лирики, прямо: использование ссылок для передачи значений снижает производительность. Мы думаем, что вместо того что бы передавать копию переменной, сценарий передает саму переменную, исходя из чего делаем вывод, что это должно работать быстрее. Увы, это заблуждение. Что бы понять почему давайте разберёмся с тем, как процессор Zend Engine обрабатывает значения.
При работе с переменными процессор Zend Engine реализует систему значений с подсчётом ссылок, копировании при записи. Это означает, что многие переменные могут указывать на одно и то же значение. При этом большое количество блоков памяти не потребляется. Рассмотрим пример:
Переменной $b присваивается значение переменной $a, при этом сами данные никуда не копируются! Вместо этого переменная $b преобразуется таким образом, что бы указывать на тоже место в памяти, где хранится переменная $a, т.е. на место хранения первоначально присвоенных данных (в нашем случае это массив со значениями). Процессор отмечает массив и увеличивает счётчик ссылок до 2-х. Рассмотрим ещё один пример:
Надеюсь, никто не ждал, что значение переменных окажется одинаковым? 🙂 Шутка. Так что же произошло, если мы тут говорили о ссылках на одно место в памяти? Когда мы начали производить модификацию массива процессор Zend Engine разделяет версии $a и $b. Как только процессор обнаруживает операцию записи по значению, на которую имеется более одной ссылки, происходит копирование данных — создаётся идентичное значение, расположенное в другом участке памяти, никак не связанным с любой другой ссылкой. И только после того как этап копирования при записи будет пройден операция будет продолжена. Такое своевременное дублирование повышает производительность без каких-либо побочных эффектов. И все благодаря исключению копирования ненужных данных!
Однако, все вышесказанное не дает ответа на вопрос «почему же передача по ссылке — зло?».
Во-первых, это бесполезно, т.к. благодаря механизму подсчёта ссылок нет необходимости в передаче переменных по ссылке. Процессор сам будет избегать ненужного копирования при малейшей возможности.
Во-вторых, процессор… так, давайте-ка лучше разберем на примере. Добавим к нашему коду функцию распечатки содержимого:
Когда процессор приступает к передаче массива $a в функции prepareArr(), он определяет, что значение (наш массив) необходимо передавать по ссылке. Далее обнаруживает, что счётчик ссылок больше 1 (в нашем случае он равен 2). Поскольку значение массива $a передается по ссылке и любые изменения, которые может внести в него наша функция, никак не должны отразиться на $b, процессор делает отдельные копии для массивов $a и $b. При передаче значения переменной в функцию Zeng Engine может просто нарастить счётчик ссылок.
Нанооптимизация, подумаете вы? Может быть, но при передаче значений по ссылке вы теряете 30% производительности этой операции. И чем больше объем данных, с которыми вы работаете, тем больше падает скорость выполнения операции.
Например, выполнение последнего примера в цикле из 50000 итераций составит 0.4538291 сек. Этот же скрипт, но без использования ссылок выполняется за 0.3090010 сек., т.е. на 30% быстрее. Если увеличить объем данных до 6,5 кб, то выполнение циклов с 5000 итераций составим 19.7765129 сек. и 7.3865049 сек. соответственно. Последняя цифра, как вы уже сами догадались, результат выполнения функции без использования ссылок.
В ключе повышения производительности не рекомендуется использовать передачу значений по ссылке. Использование ссылок оправдано только тогда, когда это имеет смысл с функциональной точки зрения.
Массивы в PHP передаются по значению или по ссылке?
когда массив передается в качестве аргумента в метод или функцию он передается по ссылке?
7 ответов
для второй части вашего вопроса см. страница массива руководства указано, что (цитирую) :
назначение массива всегда включает стоимость копирование. Используйте справочник оператора скопируйте массив по ссылке.
и приведенный пример :
Для первой части, лучший способ убедиться-это попробовать 😉
рассмотрим этот пример кода :
это даст этот вывод:
что указывает на то, что функция не изменила» внешний » массив, который был передан в качестве параметра: он передан как копия, а не ссылка.
если вы хотите, чтобы он был передан по ссылке, вам придется изменить функцию следующим образом:
как, на этот раз, массив был передан » мимо ссылка.»
Не стесняйтесь читать Ссылки Объяснили раздел руководства : он должен ответить на некоторые ваши вопросы 😉
что касается вашего первого вопроса, массив передается по ссылке, если он не изменен в вызываемом методе / функции. При попытке изменить массив в методе / функции сначала создается его копия, а затем изменяется только копия. Это заставляет думать, что массив передается по значению, когда на самом деле это не так.
однако, если вы измените массив, сначала будет сделана его копия (которая использует больше памяти, но не влияет на исходный массив).
FYI-это известно как» ленивая копия «или»копирование при записи».
TL; DR
a) метод/функция только чтение аргумент Array => неявные (внутренние) ссылки
б) метод/функция изменение аргумент Array => стоимостью
c) аргумент массива метода/функции явно помечен как ссылка (с амперсандом)=>явная (пользовательская) ссылка
или такой:
— массив без амперсанда парам!—20—>: передается по ссылке; операции записи изменяют новую копию массива, копия которого создается при первой записи;
— амперсанд array param: передается по ссылке; операции записи изменяют исходный массив.
помните-PHP делает значение-copy тот момент, когда вы пишите не амперсанд массив парам. Вот что!—6—> средства. Я бы хотел показать вам источник этого поведения, но там страшно. Лучше использовать xdebug_debug_zval ().
ответ
текст
кажется, я записываю это для себя. Мне нужен блог или что-то в этом роде.
всякий раз, когда люди говорят о ссылках (или указателях, если на то пошло), они обычно заканчиваются логомахией (просто посмотрите на это нить!).
PHP является почтенный язык, я думал, что должен добавить к путанице (хотя это резюме вышеуказанных ответов). Потому что, хотя два человека могут быть правы одновременно, вам лучше просто разбить их головы в один ответ.
во-первых, вы должны знать, что вы не педант, если не отвечаете в черно-белой манере. Все сложнее, чем»да/нет».
как вы увидите, все по значению / по ссылке вещь очень связана с тем, что именно вы делаете с этим массивом в своей области метода/функции: читаете его или модифицируете?
что говорит PHP? (он же «перемены»)
на руководство говорит это (Курсив мой):
чтобы иметь аргумент функция, всегда передаваемая по ссылке, добавляет амперсанд ( & ) к имя аргумента в определении функции
Читать далее мой попутчик.
что на самом деле делает PHP? (он же «мудрая память»)
было бы не идеально передавать огромные массивы различным функциям, а PHP-делать их копии (в конце концов, это то, что делает» pass-by-value»):
Ну, если бы это действительно было pass-by-value, у нас было бы немного 3MB+ RAM, потому что есть два копии этого массив, верно?
факты
и when an array is passed as an argument to a method or function is it passed by reference?
я придумал три (да, три) случаи:
а) метод/функция только чтение аргумент массив
б) метод/функция изменение аргумент массив
c) аргумент массива метода/функции явно помечен как ссылка (с амперсандом)
во-первых, давайте посмотрим, сколько памяти этот массив на самом деле ест (run здесь):
столько байт. Отличный.
a) метод/функцию только чтение аргумент массив
теперь давайте сделаем функцию, которая только чтение указанный массив в качестве аргумента, и мы увидим, сколько памяти занимает логика чтения:
b) метод / функция изменение аргумент массив
c) аргумент массива метод / функция явно помечен как ссылка (с амперсандом)
я уверен, что вы получите 200 максимум! Таким образом, это съедает примерно столько же памяти, сколько чтение из не амперсанд парам.
массивы объекты передаются по значению (массив), но каждый объект передается по ссылке.
Примечание: в качестве оптимизации каждое значение передается в качестве ссылки до его изменения внутри функции. Если он изменен и значение было передано по ссылке, то он копируется и копия изменяется.
когда массив передается методу или функции в PHP, он передается по значению, если вы явно не передаете его по ссылке, например:
этот поток немного старше, но здесь что-то я только что наткнулся:
попробуйте этот код:
в PHP массивы передаются функциям по значению по умолчанию, если вы явно не передаете их по ссылке, как показано в следующем фрагменте:
Php передать массив по ссылке
Вы можете передать переменную в функцию по ссылке, чтобы она могла изменять значение аргумента. Синтаксис выглядит следующим образом:
Ссылки, возвращаемые функцией, например:
Любое другое выражение не должно передаваться по ссылке, так как результат не определён. Например, следующая передача по ссылке является неправильной:
foo (new Foobar ()) // Вызывает уведомление с PHP 7.0.7
// Notice: Only variables should be passed by reference
?>
User Contributed Notes 16 notes
beware unset() destroys references
For anyone wondering, the copy-on-write behaviour just does the Right Thing™ when an array is passed to a function not by-ref which then passes it through to another function by-ref without writing to it. For example:
If you changed a reference variable with a new `Address`, the variable it originally pointed to won’t change.
I designed a class that can easily pass references.
echo test ( 1 ), PHP_EOL ; // test-1
echo TestCall :: test ( 3 ), PHP_EOL ; // test-3
Within a class, passing array elements by reference which don’t exist are added to the array as null. Compared to a normal function, this changes the behavior of the function from throwing an error to creating a new (null) entry in the referenced array with a new key.
The notes indicate that a function variable reference will receive a deprecated warning in the 5.3 series, however when calling the function via call_user_func the operation aborts without fatal error.
This is not a «bug» since it is not likely worth resolving, however should be noted in this documentation.
This function internally swaps the contents between
two simple variables using ‘passing by reference’.
Some programming languages have such a swap function
built in, but PHP seems to lack such a function. So,
one was created to fill the need. It only handles
simple, single variables, not arrays, but it is
still a very handy tool to have.
No value is actually returned by this function, but
the contents of the indicated variables will be
exchanged (swapped) after the call.
*/
$a = 123.456 ;
$b = ‘abcDEF’ ;
Some have noticed that reference parameters can not be assigned a default value. It’s actually wrong, they can be assigned a value as the other variables, but can’t have a «default reference value», for instance this code won’t compile :
?>
And this scripts output is :
Array 1 Array
(
[0] => test
[1] => test2
[indirect test] => test
)
_POST Array
(
[indirect POST test] => test
)
Of course that means you can only assign default reference to globals or super globals variables.
Beware of using references with anonymous function and «use» keyword :
agreed : this change produces less readable code.
additionally, it breaks many existing perfectly working codes which are not portable anymore and in some cases will require complex modifications
another issue regards the fatal error that is produced : how the hell am i supposed to do if i want to allow the user to use a value that is not even in a variable, or the return or a function call, or use call_user_func. this produces many occasions for a code to even break at run time
PHP has a strange behavior when passing a part of an array by reference, that does not yet exist.
. which seems to be not intentional!
Sometimes we need functions for building or modifying arrays whose elements are to be references to other variables (arrays or objects for instance). In this example, I wrote two functions ‘tst’ and ‘tst1’ that perform this task. Note how the functions are written, and how they are used.
Ссылки в PHP
Что такое ссылки
Что делают ссылки
Ссылки в PHP дают возможность двум переменным ссылаться на одно содержимое. Например:
Замечание: При копировании массива ссылок, они не разыменовываются. Это также касается массивов, передаваемых функциям по значению.
Такой же синтаксис можно использовать и в функциях, возвращая ссылки, а так же в операторе new (начиная с PHP 4.0.4):
Операция @, которая скрывает сообщения об ошибках, например в конструкторе @new, не может быть использована совместно с операцией & (&new). Это ограничение интерпретатора Zend.
Пример. Присвоение ссылок глобальным переменным внутри функции
Замечание: При использовании переменной-ссылки в foreach, изменяется содержание, на которое она ссылается.
Пример. Ссылки и foreach
Внимание: Сложные массивы в некоторых случаях могут копироваться вместо создания ссылок. например, следующий пример не будет работать как ожидалось.
Пример. Ссылки и сложные массивы
Чем ссылки не являются
Передача по ссылке
Любое другое выражение не должно передаваться по ссылке, так как результат не определён. Например, следующая передача по ссылке является неправильной:
Эти требования для PHP 4.0.4 и позже.
Возвращение по ссылке
Возвращение по ссылке используется в тех случаях, когда вы хотите использовать функцию для выбора переменной, с которой должна быть связана данная ссылка. При возвращении по ссылке используйте такой синтаксис:
В этом примере устанавливается свойство объекта, возвращённого функцией find_var, а не его копии, как было бы без использования ссылок.
Сброс переменных-ссылок
При сбросе ссылки, просто разрывается связь имени и содержимого переменной. Это не означает, что содержимое переменной будет разрушено. Например:
Опять же, можно провести аналогию с вызовом unlink (в Unix).
Неявное использование механизма ссылок
Многие синтаксические конструкции PHP реализованы через механизм ссылок, поэтому всё сказанное выше о ссылочном связывании применимо также и к этим конструкциям. Некоторые конструкции, вроде передающих и возвращающих по ссылке, рассмотрены ранее. Другие конструкции, использующие ссылки: