-
Notifications
You must be signed in to change notification settings - Fork 73
/
references.xml
601 lines (533 loc) · 23.7 KB
/
references.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: d58ee8eaaa7f716c51f66f5f1058ab3c42376d98 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[] = '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>
Удаление переменной <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
-->