mirror of
https://github.com/php/doc-ru.git
synced 2026-03-23 23:32:16 +01:00
617 lines
24 KiB
XML
617 lines
24 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
||
<!-- EN-Revision: 9463e5b660c4883b91a30f07ff68731bbcc48346 Maintainer: irker Status: ready -->
|
||
<!-- Reviewed: no -->
|
||
<chapter xml:id="language.references" xmlns="http://docbook.org/ns/docbook">
|
||
<title>Объяснение ссылок</title>
|
||
|
||
<sect1 xml:id="language.references.whatare">
|
||
<title>Что такое ссылки</title>
|
||
<simpara>
|
||
Ссылки в PHP — средство доступа к одному и тому же содержимому переменной
|
||
под разными именами. Ссылки в PHP не похожи на указатели языка C; например, нельзя выполнять
|
||
над ссылками адресную арифметику, они не хранят адрес памяти другой переменной и т. д.
|
||
Дополнительную информацию даёт раздел «<xref linkend="language.references.arent" />».
|
||
Напротив, ссылки в PHP — псевдонимы в <link linkend="features.gc.refcounting-basics">таблице имён</link> переменных.
|
||
Обратите внимание, в PHP имя переменной и её содержимое — не одно и то же,
|
||
поэтому одно и то же значение разрешается хранить под разными именами. Близкое сходство
|
||
образовывают названия файлов и сами файлы в Unix-системах:
|
||
имена переменных — записи каталога, а значение переменной — сам файл. Ссылки в PHP — аналогичны
|
||
жёстким ссылкам в файловых системах Unix.
|
||
</simpara>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="language.references.whatdo">
|
||
<title>Что делают ссылки</title>
|
||
<para>
|
||
Со ссылками выполняют три базовые операции:
|
||
<link linkend="language.references.whatdo.assign">присваивание по ссылке</link>,
|
||
<link linkend="language.references.whatdo.pass">передача по ссылке</link>
|
||
и <link linkend="language.references.whatdo.return">возврат по ссылке</link>.
|
||
Глава знакомит читателя с этими операциями и даёт ссылки
|
||
на дополнительные материалы для изучения.
|
||
</para>
|
||
<sect2 xml:id="language.references.whatdo.assign">
|
||
<title>Присваивание по ссылке</title>
|
||
<para>
|
||
Первое, что делают ссылки в PHP, — разрешают создавать две переменные,
|
||
которые ссылаются на одно и то же значение. Когда выражение записывают вот так:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$a =& $b;
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
переменные <varname>$a</varname> и <varname>$b</varname> указывают
|
||
на одно и то же значение.
|
||
<note>
|
||
<para>
|
||
Переменные <varname>$a</varname> и <varname>$b</varname>, которые приводит пример, — эквивалентны.
|
||
Переменная <varname>$a</varname> не указывает на переменную <varname>$b</varname>
|
||
или наоборот. Переменные <varname>$a</varname>
|
||
и <varname>$b</varname> указывают на одно и то же значение.
|
||
</para>
|
||
</note>
|
||
</para>
|
||
<note>
|
||
<para>
|
||
PHP создаст переменную, если неинициализированную переменную
|
||
присвоили, передали или вернули по ссылке.
|
||
<example>
|
||
<title>Пример присваивания ссылок с неопределёнными переменными</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo(&$var) {}
|
||
|
||
foo($a); // PHP создал переменную $a и присвоил ей значение null
|
||
|
||
$b = array();
|
||
foo($b['b']);
|
||
var_dump(array_key_exists('b', $b)); // bool(true)
|
||
|
||
$c = new stdClass();
|
||
foo($c->d);
|
||
var_dump(property_exists($c, 'd')); // bool(true)
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
</note>
|
||
<para>
|
||
Таким же синтаксисом разрешается пользоваться при вызове функций, из которых возвращаются ссылки на значения:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$foo =& find_var($bar);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
<para>
|
||
Обращение через такой синтаксис к функции, которая <emphasis>не</emphasis> возвращает значение по ссылке,
|
||
выдаст ошибку, равно как и обращение через такой синтаксис
|
||
к результату, который возвращает оператор <link linkend="language.oop5.basic.new">new</link>.
|
||
Объекты хотя и передаются как указатели, это не то же, что ссылки, как объясняет
|
||
раздел «<link linkend="language.oop5.references">Объекты и ссылки</link>».
|
||
</para>
|
||
<warning>
|
||
<para>
|
||
Ссылка будет видна только внутри функции, если присвоить ссылку переменной,
|
||
которую объявили внутри функции через ключевое слово <literal>global</literal>.
|
||
Чтобы избежать этого и сделать ссылку видимой в глобальном контексте,
|
||
ссылку присваивают переменной суперглобального массива <varname>$GLOBALS</varname>.
|
||
<example>
|
||
<title>
|
||
Пример присваивания ссылок переменным, которые объявили внутри функции через ключевое слово global
|
||
</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$var1 = "Пример переменной";
|
||
$var2 = "";
|
||
|
||
function global_references($use_globals)
|
||
{
|
||
global $var1, $var2;
|
||
|
||
if (!$use_globals) {
|
||
$var2 =& $var1; // Ссылка $var1 видна только внутри функции
|
||
} else {
|
||
$GLOBALS["var2"] =& $var1; // Ссылка $var1 видна также в глобальном контексте
|
||
}
|
||
}
|
||
|
||
global_references(false);
|
||
echo "Переменной \$var2 установили значение '$var2'\n"; // Переменной $var установили значение ''
|
||
|
||
global_references(true);
|
||
echo "Переменной \$var2 установили значение '$var2'\n"; // Переменной $var установили значение 'Пример переменной'
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
Об инструкции <literal>global $var;</literal> думают как о сокращённой записи
|
||
выражения <literal>$var =& $GLOBALS['var'];</literal>, в котором переменной
|
||
присваивается ссылка. Поэтому присваивание переменной <literal>$var</literal> другой ссылки
|
||
изменяет ссылку только локальной переменной.
|
||
</para>
|
||
</warning>
|
||
<note>
|
||
<para>
|
||
Когда в инструкции &foreach; значение присваивается переменной, которая хранит ссылку,
|
||
значение ссылки тоже изменяется.
|
||
<example>
|
||
<title>Пример ссылок в конструкции foreach</title>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$ref = 0;
|
||
$row =& $ref;
|
||
|
||
foreach (array(1, 2, 3) as $row) {
|
||
// Сделать что-нибудь
|
||
}
|
||
|
||
echo $ref; // 3 — значение последнего элемента массива, который перебирался в цикле
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</example>
|
||
</para>
|
||
</note>
|
||
<para>
|
||
Выражения с языковой конструкцией <link linkend="function.array"><literal>array()</literal></link>
|
||
умеют вести себя как присваивание по ссылке, хотя и не через строгий синтаксис присваивания по ссылке,
|
||
а путём добавления префикса <literal>&</literal> к добавляемому элементу массива. Приведём пример:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$a = 1;
|
||
$b = array(2, 3);
|
||
|
||
$arr = array(&$a, &$b[0], &$b[1]);
|
||
|
||
$arr[0]++;
|
||
$arr[1]++;
|
||
$arr[2]++;
|
||
/* $a == 2, $b == array(3, 4); */
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
<para>
|
||
Однако обратите внимание, что ссылки внутри массивов несут опасность.
|
||
Стандартные (не по ссылке) присваивания со ссылкой в правой части
|
||
не превращают левую часть в ссылку, но ссылки внутри массивов сохраняются
|
||
при стандартных присваиваниях.
|
||
Это также относится к вызовам функций, в которых массив передаётся по значению. Приведём пример:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
/* Присваивание скалярных переменных */
|
||
$a = 1;
|
||
$b =& $a;
|
||
$c = $b;
|
||
$c = 7; // Переменная $c — не ссылка; переменные $a и $b не изменились
|
||
|
||
/* Присваивание переменных, которые содержат массив */
|
||
$arr = array(1);
|
||
$a =& $arr[0]; // Переменные $a и $arr[0] входят в один набор ссылок
|
||
$arr2 = $arr; // Присваивание по значению, а не по ссылке!
|
||
$arr2[0]++;
|
||
/* $a == 2, $arr == array(2) */
|
||
/* Содержимое переменной $arr изменяется, даже если это не ссылка! */
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
Другими словами, ссылочное поведение массивов определяется поэлементно;
|
||
ссылочное поведение отдельных элементов массива не зависит от ссылочного статуса
|
||
контейнера массива.
|
||
</para>
|
||
</sect2>
|
||
<sect2 xml:id="language.references.whatdo.pass">
|
||
<title>Передача по ссылке</title>
|
||
<para>
|
||
Второе, что умеют делать ссылки, — передавать переменные по ссылке. Для этого создают
|
||
две переменные, которые ссылаются на одно и то же содержимое: одну — в функции, а другую —
|
||
в области видимости вызова. Следующий пример:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo(&$var)
|
||
{
|
||
$var++;
|
||
}
|
||
|
||
$a = 5;
|
||
foo($a);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
изменит значение, на которое указывает переменная <varname>$a</varname>, на 6. Причина состоит в том,
|
||
что в функции <varname>foo</varname> переменная <varname>$var</varname>
|
||
ссылается на то же содержимое, что и переменная <varname>$a</varname>. Дополнительную
|
||
информацию об этом даёт раздел
|
||
<link linkend="language.references.pass">о передаче по ссылке</link>.
|
||
</para>
|
||
</sect2>
|
||
<sect2 xml:id="language.references.whatdo.return">
|
||
<title>Возврат ссылок</title>
|
||
<para>
|
||
Третье, что умеют делать ссылки, — <link
|
||
linkend="language.references.return">возвращать по ссылке</link>.
|
||
</para>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="language.references.arent">
|
||
<title>Что ссылки собой не представляют</title>
|
||
<para>
|
||
Как говорилось в предыдущих разделах, ссылки — не указатели.
|
||
Следующая конструкция не будет делать то, что ожидается:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo(&$var)
|
||
{
|
||
$var =& $GLOBALS["baz"];
|
||
}
|
||
|
||
foo($bar);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
<simpara>
|
||
Пример выполняет следующее: в функции <varname>foo</varname> переменная <varname>$var</varname>
|
||
связывается с переменной <varname>$bar</varname>, которую PHP создал в месте вызова,
|
||
но затем повторно связывается с переменной <varname>$GLOBALS["baz"]</varname>. Через механизм ссылок невозможно
|
||
связать переменную <varname>$bar</varname> с другим значением в области видимости вызова,
|
||
поскольку у функции <varname>foo</varname> нет доступа к переменной <varname>$bar</varname>,
|
||
которую представляет только переменная <varname>$var</varname>,
|
||
которой доступно только содержимое переменной <varname>$bar</varname>,
|
||
но недоступна связка имя-значение, которую хранит <link linkend="features.gc.refcounting-basics">таблица символов</link> области видимости вызова.
|
||
Привязать внешнюю переменную к другому значению помогает
|
||
<link linkend="language.references.return">механизм возврата ссылок</link>,
|
||
который связывает ссылки с переменными, которые выбрала функция.
|
||
</simpara>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="language.references.pass">
|
||
<title>Передача по ссылке</title>
|
||
<para>
|
||
Переменную по ссылке разрешается передавать в функцию, чтобы
|
||
функция изменила переменную. Синтаксис выглядит вот так:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo(&$var)
|
||
{
|
||
$var++;
|
||
}
|
||
|
||
$a = 5;
|
||
foo($a);
|
||
// В этом месте переменная $a указывает на значение 6
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
<note>
|
||
<simpara>
|
||
В вызове функции отсутствует знак ссылки — знак
|
||
указывают только в определении функции. Определения функции достаточно,
|
||
чтобы правильно передать аргумент по ссылке.
|
||
</simpara>
|
||
</note>
|
||
</para>
|
||
<para>
|
||
По ссылке разрешается передавать:
|
||
<itemizedlist>
|
||
<listitem>
|
||
<simpara>
|
||
Переменные: <literal>foo($a)</literal>
|
||
</simpara>
|
||
</listitem>
|
||
<listitem>
|
||
<para>
|
||
Ссылки, которые возвращаются функциями:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo(&$var)
|
||
{
|
||
$var++;
|
||
}
|
||
|
||
function &bar()
|
||
{
|
||
$a = 5;
|
||
return $a;
|
||
}
|
||
|
||
foo(bar());
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
Подробнее об этом рассказывает раздел <link
|
||
linkend="language.references.return">о возврате по ссылке</link>.
|
||
</para>
|
||
</listitem>
|
||
</itemizedlist>
|
||
</para>
|
||
<para>
|
||
Другие выражения не передают по ссылке, поскольку результат
|
||
будет неопределённым. Следующие примеры передачи по ссылке неправильные:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function foo(&$var)
|
||
{
|
||
return $var++;
|
||
}
|
||
|
||
// Обратите внимание, перед названием функции отсутствует знак &
|
||
function bar()
|
||
{
|
||
$a = 5;
|
||
return $a;
|
||
}
|
||
|
||
foo(bar()); // Выдаёт предупреждение
|
||
|
||
foo($a = 5); // Выражение, а не переменная
|
||
foo(5); // Константа, а не переменная
|
||
|
||
class Foobar {}
|
||
|
||
foo(new Foobar()); // Вызывает уведомление с PHP 7.0.7
|
||
// Notice: Only variables should be passed by reference
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="language.references.return">
|
||
<title>Возврат ссылок</title>
|
||
<para>
|
||
Возврат по ссылке приносит пользу, когда определить переменную, к которой требуется привязать ссылку,
|
||
нужно через функцию. Возвратом по ссылке <emphasis>не</emphasis> пользуются
|
||
для повышения производительности. Ядро PHP само оптимизирует производительность.
|
||
Ссылки возвращают только по веским техническим причинам.
|
||
Ссылки возвращает следующий синтаксис:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
class Foo
|
||
{
|
||
public $value = 42;
|
||
|
||
public function &getValue()
|
||
{
|
||
return $this->value;
|
||
}
|
||
}
|
||
|
||
$obj = new Foo();
|
||
$myValue = &$obj->getValue(); // Переменная $myValue — ссылка на переменную $obj->value, значение которой равно 42
|
||
$obj->value = 2;
|
||
echo $myValue; // Выводит новое значение свойства $obj->value — 2
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
Пример установит значение свойству объекта, ссылку на которое
|
||
вернул метод <varname>getValue</varname>, а не копии свойства, как было бы без
|
||
синтаксиса ссылок.
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Передача аргумента по ссылке отличается от возврата по ссылке тем,
|
||
что для возврата по ссылке знак <literal>&</literal>
|
||
придётся указать в двух местах — чтобы указать, что требуется возврат ссылки на свойство,
|
||
а не копии свойства, и чтобы указать, что переменную <varname>$myValue</varname>
|
||
требуется связать со ссылкой, а не присвоить переменной значение стандартным способом.
|
||
</simpara>
|
||
</note>
|
||
<note>
|
||
<simpara>
|
||
Возврат ссылки из функции синтаксисом:
|
||
<literal>return ($this->value);</literal> <emphasis>не</emphasis> сработает,
|
||
поскольку по ссылке возвращается результат <emphasis>выражения</emphasis>, а не переменная.
|
||
По ссылке разрешается возвращать только переменные и больше ничего.
|
||
</simpara>
|
||
</note>
|
||
<para>
|
||
Чтобы использовать ссылку, которую вернула функция, потребуется
|
||
присвоить ссылку переменной:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function &collector()
|
||
{
|
||
static $collection = array();
|
||
return $collection;
|
||
}
|
||
|
||
$collection = &collector();
|
||
// Переменная $collection стала ссылкой на статический массив внутри функции
|
||
|
||
$collection[] = 'foo';
|
||
|
||
print_r(collector());
|
||
// Array
|
||
// (
|
||
// [0] => foo
|
||
// )
|
||
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
<note>
|
||
<simpara>
|
||
При присваивании без символа <literal>&</literal> в выражении наподобие <code>$collection = collector();</code>
|
||
переменная <varname>$collection</varname> получит копию значения, а не ссылку, которую вернула функция.
|
||
</simpara>
|
||
</note>
|
||
Ссылку, которую вернула одна функция, передают в другую функцию,
|
||
которая принимает ссылку, следующим синтаксисом:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
function &collector()
|
||
{
|
||
static $collection = array();
|
||
return $collection;
|
||
}
|
||
|
||
array_push(collector(), 'foo');
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
<note>
|
||
<simpara>
|
||
Обратите внимание, что вызов <literal>array_push(&collector(), 'foo');</literal>
|
||
<emphasis>не</emphasis> сработает, а выдаст фатальную ошибку.
|
||
</simpara>
|
||
</note>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="language.references.unset">
|
||
<title>Удаление ссылок</title>
|
||
<para>
|
||
При удалении ссылки просто разрывается связь между именем переменной
|
||
и содержимым переменной. Содержимое переменной не уничтожается.
|
||
Например:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$a = 1;
|
||
$b =& $a;
|
||
unset($a);
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
Пример не удалит переменную <varname>$b</varname>, удалится только переменная <varname>$a</varname>.
|
||
</para>
|
||
<simpara>
|
||
Опять же, было бы полезно рассматривать это как аналог
|
||
вызова функции <command>unlink</command> в системе Unix.
|
||
</simpara>
|
||
</sect1>
|
||
|
||
<sect1 xml:id="language.references.spot">
|
||
<title>Неявная работа механизма ссылок</title>
|
||
<simpara>
|
||
Многие синтаксические конструкции в PHP реализовали через механизм ссылок.
|
||
Поэтому информация этого раздела о ссылочном связывании касается
|
||
и этих конструкций. Отдельные конструкции наподобие передачи и возврата
|
||
по ссылке, объяснили другие подразделы. Другие конструкции с синтаксисом ссылок:
|
||
</simpara>
|
||
|
||
<sect2 xml:id="references.global">
|
||
<title>Ссылки global</title>
|
||
<para>
|
||
При объявлении переменной синтаксисом <command>global $var</command>
|
||
фактически создаётся ссылка на глобальную переменную. Такое объявление —
|
||
то же, что и:
|
||
<informalexample>
|
||
<programlisting role="php">
|
||
<![CDATA[
|
||
<?php
|
||
|
||
$var =& $GLOBALS["var"];
|
||
|
||
?>
|
||
]]>
|
||
</programlisting>
|
||
</informalexample>
|
||
</para>
|
||
<simpara>
|
||
Удаление переменной <varname>$var</varname> конструкцией unset()
|
||
не удалит глобальную переменную.
|
||
</simpara>
|
||
</sect2>
|
||
</sect1>
|
||
|
||
</chapter>
|
||
<!-- Keep this comment at the end of the file
|
||
Local variables:
|
||
mode: sgml
|
||
sgml-omittag:t
|
||
sgml-shorttag:t
|
||
sgml-minimize-attributes:nil
|
||
sgml-always-quote-attributes:t
|
||
sgml-indent-step:1
|
||
sgml-indent-data:t
|
||
indent-tabs-mode:nil
|
||
sgml-parent-document:nil
|
||
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
||
sgml-exposed-tags:nil
|
||
sgml-local-catalogs:nil
|
||
sgml-local-ecat-files:nil
|
||
End:
|
||
vim600: syn=xml fen fdm=syntax fdl=2 si
|
||
vim: et tw=78 syn=sgml
|
||
vi: ts=1 sw=1
|
||
-->
|