mirror of
https://github.com/php/doc-ru.git
synced 2026-03-26 00:32:15 +01:00
541 lines
21 KiB
XML
541 lines
21 KiB
XML
<?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 =& $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>$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>&</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(&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
|
||
-->
|