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 передача по ссылке в функцию

To experiment on performance of pass-by-reference and pass-by-value, I used this script. Conclusions are below.

3 valuue yes 129 s
4 reference yes 66 us

1. PHP is already smart about zero-copy / copy-on-write. A function call does NOT copy the data unless it needs to; the data is
only copied on write. That’s why #1 and #2 take similar times, whereas #3 takes 2 million times longer than #4.
[You never need to use &$array to ask the compiler to do a zero-copy optimisation; it can work that out for itself.]

2. You do use &$array to tell the compiler «it is OK for the function to over-write my argument in place, I don’t need the original
any more.» This can make a huge difference to performance when we have large amounts of memory to copy.
(This is the only way it is done in C, arrays are always passed as pointers)

3. The other use of & is as a way to specify where data should be *returned*. (e.g. as used by exec() ).
(This is a C-like way of passing pointers for outputs, whereas PHP functions normally return complex types, or multiple answers
in an array)

5. Sometimes, pass by reference could be at the choice of the caller, NOT the function definitition. PHP doesn’t allow it, but it
would be meaningful for the caller to decide to pass data in as a reference. i.e. «I’m done with the variable, it’s OK to stomp
on it in memory».
*/
?>

A function’s argument that is an object, will have its properties modified by the function although you don’t need to pass it by reference.

In function calls, PHP clearly distinguishes between missing arguments and present but empty arguments. Thus:

The best approach, it seems to me, is to always use a sentinel like null as the default value of an optional argument. This way, callers like g and g’s clients have many options, and furthermore, callers always know how to omit arguments so they can omit one in the middle of the parameter list.

PASSING A «VARIABLE-LENGTH ARGUMENT LIST OF REFERENCES» TO A FUNCTION
As of PHP 5, Call-time pass-by-reference has been deprecated, this represents no problem in most cases, since instead of calling a function like this:
myfunction($arg1, &$arg2, &$arg3);

provided you have defined your function as
function myfuncion($a1, &$a2, &$a3) < // so &$a2 and &$a3 are
// declared to be refs.
.
>

In the following code I tried to amend this by using the
array() language-construct as the actual argument in the
call to the function.

Источник

Отрицательная сторона передачи значений по ссылкам

php передача по ссылке в функцию. Смотреть фото php передача по ссылке в функцию. Смотреть картинку php передача по ссылке в функцию. Картинка про 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 Extension: тонкости

Публикую топик, за который получил инвайт на Хабр =)

Давно подумывал поделиться опытом разработки расширений для PHP, но все время забывал =)
Сейчас, увидев хабратопик об основах создания расширений для PHP в VS2008, решил наконец это сделать.
Поскольку основы были изложены в этом топике, я сразу перейду к более тонким моментам.

Вывод текста

Если необходимо вывести текст, вместо стандартной функции printf() следует пользоваться функцией zend_printf(). Если вызвавший нас скрипт запущен для обработки HTTP-запроса, выводимая через zend_printf() информация будет отправлена напрямую клиенту. При запуске же php в режиме standalone — выведет текст на экран.

Передача параметров функции по ссылке

Поскольку начиная с PHP 5.3.0 передача аргумента функции по ссылке при вызове функции — deprecated, аргумент следует объявлять как передаваемый по ссылке в объявлении функции. В случае, когда функцию мы объявляем в PHP — все просто — достаточно перед именем аргумента поставить амперсанд, например вот так:

Если же функцию мы объявляем в расширении — все несколько сложнее.
Для начала следует описать аргументы функции:

ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args)
ZEND_ARG_INFO(pass_by_ref, name)
.
ZEND_END_ARG_INFO()

Параметры макроса ZEND_BEGIN_ARG_INFO_EX():
name — Имя структуры, описывающей данный список аргументов. Должно быть уникальным. Например, для функции ReadData() структуру можно назвать arginfo_readdata.
required_num_args — Количество обязательных аргументов функции.
pass_rest_by_reference — Следует ли остальные (необязательные) аргументы передавать по ссылке (0 — нет, 1 — да).
return_reference — Передается ли возвращаемое значение по ссылке.

Параметры макроса ZEND_ARG_INFO():
pass_by_ref — Передавать ли этот аргумент по ссылке.
name — Имя аргумента.

Все аргументы перечисляются в том же порядке, в каком они передаются функции.
Пример объявления той же функции ReadData:

ZEND_BEGIN_ARG_INFO_EX(arginfo_readdata,0,0,2)
ZEND_ARG_INFO(0,id)
ZEND_ARG_INFO(1,data)
ZEND_END_ARG_INFO()

После этого при объявлении функции достаточно указать в качестве второго параметра макроса PHP_FE() название нашей структуры описания аргументов. Например:

Что такое zval и с чем его едят

zval — это структура, содержащая представление PHP-переменной. В ней может содержаться как скалярное значение (число, строка, и т.п.), так и массив или handle ресурса.
Если мы хотим принять в качестве аргумента функции расширения или вернуть из функции массив — нам придется работать именно с этим zval.

Получаем zval

К примеру мы хотим получить в качестве аргумента функции ассоциативный массив и получить из него значения по некоторым индексам.
Для этого следует: объявить указатель на zval; при вызове функции zend_parse_parameters указать тип аргумента «a»; передать ей же указатель на объявленный указатель на zval.
Сразу пример кода:

Получаем значения из массива

В данном примере широко используются макросы Zend.
Z_TYPE_*() возвращает тип, содержащийся в переданном ему zval. Значения, как можно догадаться, имеют вид IS_тип. Например, IS_ARRAY или IS_STRING.
Z_ARRVAL_*() возвращает указатель на структуру HashTable, которая представляет собой внутреннее представление массива PHP.
Z_LVAL_*() возвращает число, содержащееся в переданном zval.
* — может быть P или PP, в зависимости от того, передаем мы указатель на zval или указатель на указатель на zval.
Функция zend_hash_find(zval *) ищет в переданном HashTable указанный индекс.
Остальное должно быть понятно.
Приведенный код разумеется некрасив и неоптимален, он тут исключительно для примера =)

Заключение

Не знаю, насколько интересна эта тема хабрасообществу, поэтому пока не буду расписывать дальше.
Если тема окажется интересной, буду рад рассказать о других тонкостях создания функций в расширениях.

Буду рад услышать любые замечания по топику и по стилю, все таки это мой первый хабратопик =)

Источник

Объекты передаются по ссылке или нет?

Часто можно услышать фразу, что в PHP «объекты всегда передаются по ссылке». На самом деле всё немного сложнее.

Как выглядит работа с ссылками в PHP? Для этого используется специальный синтаксис – перед именем переменной или параметра функции ставится символ амперсанда (&). В том случае, когда амперсанд проставлен в сигнатуре функции – это называют передачей параметра по ссылке. Изменяя такую переменную-параметр внутри функции, после выхода из функции мы обнаружим, что значение поменялось и в месте вызова. Думаю, с этим знакомы все.

А что с объектами? Объекты, переданные внутрь какой-то функции в качестве аргументов, ведут себя точно также – если внутри функции мы меняем внутреннее состояние объекта, то снаружи увидим это изменённое состояние. Отличие в том, что в сигнатуре функции не нужно ставить амперсанд перед параметром-объектом.

php передача по ссылке в функцию. Смотреть фото php передача по ссылке в функцию. Смотреть картинку php передача по ссылке в функцию. Картинка про php передача по ссылке в функцию. Фото php передача по ссылке в функцию

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

А что, если в сигнатуре функции, принимающей объект всё-таки поставить амперсанд? После небольшой проверки, на первый взгляд, ничего не поменяется! Кажется очередной фрактал плохого дизайна: скалярные типы данных можно передать двумя способами, и по ссылке, и по значению, а объекты всегда по ссылке, при этом амперсанд хочешь ставь, хочешь не ставь.

На самом деле, это заблуждение. Разберёмся что здесь происходит.

Упрощённо, механику можно представить так: когда мы создаём объект с помощью оператора new и присваиваем какой-то переменной, в эту переменную помещается не сам объект, а некий идентификатор объекта, id.

Таким образом снаружи функции и внутри мы, имея одинаковое значение идентификатора объекта, работаем с одним и тем же объектом.

Но если внутри функции мы присвоим переменной, например null – повлияет ли это на объект снаружи функции? Никак! Мы обнулили переменную содержащую id объекта внутри функции, но снаружи функции, внешняя переменная всё ещё содержит id объекта и сам объект никуда не делся из памяти.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *