1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-23 23:32:16 +01:00
Files
archived-doc-ru/language/references.xml
2025-04-10 16:38:24 +03:00

617 lines
24 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?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 =&amp; $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>&amp;</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>&amp;</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>&amp;</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(&amp;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
-->