1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-26 00:32:15 +01:00
Files
archived-doc-ru/language/references.xml
2023-02-14 09:17:44 +03:00

541 lines
21 KiB
XML
Raw 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: 6d29533483657c036e49edb5ea88c7103d126681 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 - это средство доступа к содержимому одной переменной под
разными именами. Они не похожи на указатели C; например, вы не можете выполнять
над ними адресную арифметику, они не являются реальными адресами в памяти и т.д.
Для получения дополнительной информации смотрите <xref linkend="language.references.arent" />.
Вместо этого указатели в PHP - это псевдонимы в таблице имён переменных.
В 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>
При присвоении, передаче или возврате неинициализированной переменной по ссылке,
происходит её создание.
<example>
<title>Использование ссылок с неинициализированными переменными</title>
<programlisting role="php">
<![CDATA[
<?php
function foo(&$var) { }
foo($a); // $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>
Такой же синтаксис может использоваться в функциях, возвращающими ссылки,
и с оператором <literal>new</literal>:
<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>Присвоение ссылок глобальным переменным внутри функции</title>
<programlisting role="php">
<![CDATA[
<?php
$var1 = "Пример переменной";
$var2 = "";
function global_references($use_globals)
{
global $var1, $var2;
if (!$use_globals) {
$var2 =& $var1; // только локально
} else {
$GLOBALS["var2"] =& $var1; // глобально
}
}
global_references(false);
echo "значение var2: '$var2'\n"; // значение var2: ''
global_references(true);
echo "значение var2: '$var2'\n"; // значение var2: 'Пример переменной'
?>
]]>
</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>$var</varname> в функции <varname>foo</varname> будет
связана с <varname>$bar</varname> в вызывающем коде, но затем она будет
перепривязана к <varname>$GLOBALS["baz"]</varname>. Нет способа связать
<varname>$bar</varname> в области видимости вызывающем коде с чем-либо ещё
путём использования механизма ссылок, поскольку <varname>$bar</varname> не
доступна в функции <varname>foo</varname> (доступно лишь её значение через
<varname>$var</varname>, но <varname>$var</varname> имеет только значение
переменной и не имеет связи имя-значение в таблице имён переменных).
Вы можете воспользоваться <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) {
$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[] = 'foo';
?>
]]>
</programlisting>
</informalexample>
Для передачи возвращаемой ссылки в другую функцию, принимающую ссылку, вы можете
использовать следующий синтаксис:
<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>
Это значит, например, что сброс (unset) <varname>$var</varname> не
приведёт к сбросу глобальной переменной.
</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
-->