1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-25 16:22:18 +01:00
Files
archived-doc-ru/language/namespaces.xml
2024-02-13 14:08:37 +03:00

1674 lines
70 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: 874f7c1266d4e4f2e1e6c79b5fb48b590caa1197 Maintainer: mch Status: ready -->
<!-- Reviewed: no -->
<chapter xml:id="language.namespaces" xmlns="http://docbook.org/ns/docbook"
version="1.1">
<title>Пространства имён</title>
<sect1 xml:id="language.namespaces.rationale">
<title>Обзор пространств имён</title>
<titleabbrev>Обзор</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<simpara>
Пространства имён, в широком смысле, — способ инкапсуляции
элементов. Такое абстрактное понятие встречается часто. Например, в каждой
операционной системе директории группируют связанные файлы и выступают
в роли пространства имён для находящихся в них файлов. Конкретный пример,
разрешается размещать файл <literal>foo.txt</literal> сразу в обоих каталогах:
<literal>/home/greg</literal> и <literal>/home/other</literal>, но двум копиям
файла <literal>foo.txt</literal> нельзя сосуществовать в одной директории. Кроме сказанного, для доступа
к файлу <literal>foo.txt</literal> извне каталога <literal>/home/greg</literal> надо
через разделитель добавить перед именем файла имя директории, чтобы получить
путь <literal>/home/greg/foo.txt</literal>. Этот же принцип распространяется и на пространства
имён в программировании.
</simpara>
<simpara>
В PHP пространства имён решают две проблемы, с которыми
сталкиваются авторы библиотек и приложений, когда создают переиспользуемые
элементы кода, например классы и функции:
</simpara>
<para>
<orderedlist>
<listitem>
<simpara>
Устраняют конфликт имён между кодом разработчика
и внутренними или внешними классами, функциями, константами PHP.
</simpara>
</listitem>
<listitem>
<simpara>
Создают псевдонимы (или сокращения) для Ну_Очень_Длинных_Имён, чтобы сгладить
первую проблему и улучшить читаемость исходного кода.
</simpara>
</listitem>
</orderedlist>
</para>
<simpara>
Пространства имён в PHP помогают группировать логически связанные
классы, интерфейсы, функции и константы.
</simpara>
<example>
<title>Пример синтаксиса с пространством имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace my\name; // Смотрите раздел «Определение пространств имён»
class MyClass {}
function myfunction() {}
const MYCONST = 1;
$a = new MyClass;
$c = new \my\name\MyClass; // Смотрите раздел «Глобальное пространство»
$a = strlen('hi'); // Смотрите раздел «Пространства имён: возврат
// к глобальному пространству для функций и констант»
$d = namespace\MYCONST; // Смотрите раздел «Ключевое слово namespace и магическая константа __NAMESPACE__»
$d = __NAMESPACE__ . '\MYCONST';
echo constant($d); // Смотрите раздел «Пространства имён и динамические особенности языка»
?>
]]>
</programlisting>
</example>
<note>
<simpara>
Имена пространств имён регистронезависимы.
</simpara>
</note>
<note>
<para>
Название пространства имён «<literal>PHP</literal>» и составные названия,
которые начинаются с этого слова (например, <literal>PHP\Classes</literal>), зарезервированы
для внутренних целей языка, их не нужно писать в пользовательском коде.
</para>
</note>
</sect1>
<sect1 xml:id="language.namespaces.definition">
<title>Определение пространств имён</title>
<titleabbrev>Пространства имён</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Хотя любой корректный PHP-код разрешается размещать внутри пространства имён, только
классы (включая абстрактные и трейты), интерфейсы, функции и константы зависят от него.
</para>
<para>
Пространства имён объявляют, указывая зарезервированное слово <literal>namespace</literal>.
Пространства имён в файлах объявляют в начале,
перед любым другим кодом, кроме зарезервированного слова
<xref linkend="control-structures.declare" />.
<example>
<title>Объявление единого пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
]]>
</programlisting>
</example>
<note>
<simpara>
Абсолютные имена (т. е. имена, которые начинаются с обратной косой черты)
не допускаются в объявлениях пространства имён,
поскольку языковые конструкции с начальным слешем интерпретируются
как относительные выражения пространства имён.
</simpara>
</note>
Только выражение <literal>declare</literal> разрешено помещать перед объявлением
пространства имён, чтобы определить кодировку исходного файла. В дополнение,
никакой код, кроме PHP-кода, нельзя размещать перед объявлением пространства имён, включая лишние пробелы:
<example>
<title>Объявление простого пространства имён</title>
<programlisting role="php">
<![CDATA[
<html>
<?php
namespace MyProject; // fatal error — объявление пространства имён должно быть первым выражением в скрипте
?>
]]>
</programlisting>
</example>
</para>
<para>
Кроме того, одно и то же пространство имён,
в отличие от остальных конструкций PHP,
допустимо определять в нескольких файлах,
что помогает распределять содержание файлов по файловой системе.
</para>
</sect1>
<sect1 xml:id="language.namespaces.nested">
<title>Определение подпространств имён</title>
<titleabbrev>Подпространства имён</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Так же как файлы и каталоги, пространства имён PHP разрешают создавать
иерархию имён. Поэтому имя пространства разрешено определять
с подуровнями:
<example>
<title>Определение пространства имён с иерархией</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject\Sub\Level;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
]]>
</programlisting>
</example>
Приведённый пример создаёт константу <literal>MyProject\Sub\Level\CONNECT_OK</literal>,
класс <literal>MyProject\Sub\Level\Connection</literal> и функцию
<literal>MyProject\Sub\Level\connect</literal>.
</para>
</sect1>
<sect1 xml:id="language.namespaces.definitionmultiple">
<title>Описание нескольких пространств имён в одном файле</title>
<titleabbrev>Несколько пространств имён в одном файле</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
В одном файле разрешено объявлять несколько пространств имён.
Есть два разрешённых синтаксиса:
</para>
<para>
<example>
<title>Описание нескольких пространств имён, простой синтаксис</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
namespace AnotherProject;
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
?>
]]>
</programlisting>
</example>
</para>
<para>
Этот синтаксис не рекомендован для комбинирования пространств имён в одном файле.
Вместо него лучше пользоваться альтернативным синтаксисом со скобками.
</para>
<para>
<example>
<title>Описание нескольких пространств имён, синтаксис со скобками</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace AnotherProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
?>
]]>
</programlisting>
</example>
</para>
<para>
Практика написания кода настоятельно не рекомендует объединять пространства имён
в одном файле. Главный сценарий того, когда это потребуется, —
объединение нескольких PHP-файлов в один файл.
</para>
<para>
Для объединения кода в глобальном пространстве имён с кодом в других пространствах имён
пользуются только синтаксисом со скобками. Глобальный код должен быть
помещён в конструкцию описания пространства имён без указания имени:
<example>
<title>Описание глобального и обычного пространства имён в одном файле</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // Глобальный код
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
]]>
</programlisting>
</example>
</para>
<para>
Никакой PHP-код нельзя размещать за пределами скобок пространства имён, кроме
начального выражения declare.
<example>
<title>Описание глобального и обычного пространства имён в одном файле</title>
<programlisting role="php">
<![CDATA[
<?php
declare(encoding='UTF-8');
namespace MyProject {
const CONNECT_OK = 1;
class Connection { /* ... */ }
function connect() { /* ... */ }
}
namespace { // Глобальный код
session_start();
$a = MyProject\connect();
echo MyProject\Connection::start();
}
?>
]]>
</programlisting>
</example>
</para>
</sect1>
<sect1 xml:id="language.namespaces.basics">
<title>Пространства имён: основы</title>
<titleabbrev>Основы</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Прежде чем обсуждать работу с пространствами имён, важно понять, как PHP узнаёт,
какие элементы из пространства имён запрашиваются в коде. Можно провести
аналогию между пространствами имён PHP и файловой системой. Есть три способа обратиться
к файлу в файловой системе:
<orderedlist>
<listitem>
<simpara>
Относительное имя файла наподобие <literal>foo.txt</literal> разрешится
в <literal>currentdirectory/foo.txt</literal>, где <literal>currentdirectory</literal> — текущая
директория, в которой мы находимся. Тогда, если текущая директория —
<literal>/home/foo</literal>, то имя преобразуется в <literal>/home/foo/foo.txt</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Относительное имя пути наподобие <literal>subdirectory/foo.txt</literal> разрешится
в <literal>currentdirectory/subdirectory/foo.txt</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Абсолютное имя пути наподобие <literal>/main/foo.txt</literal> останется
таким же: <literal>/main/foo.txt</literal>.
</simpara>
</listitem>
</orderedlist>
Тот же принцип сохранится при разрешении элементов из пространств имён PHP. Например,
имя класса разрешено указывать тремя способами:
<orderedlist>
<listitem>
<simpara>
Неполное имя, или имя класса без префикса, наподобие
<literal>$a = new foo();</literal> или
<literal>foo::staticmethod();</literal>. Если текущее пространство имён —
<literal>currentnamespace</literal>, то это имя разрешится
в <literal>currentnamespace\foo</literal>. В коде в глобальном
пространстве имён имя останется таким же: <literal>foo</literal>.
</simpara>
<simpara>
Предостережение: неполные имена функций и констант будут разрешатся
в глобальные функции и константы, если они не определены в текущем пространстве имён.
Подробнее об этом рассказано в разделе
«<link linkend="language.namespaces.fallback">
Пространства имён: возврат к глобальному пространству для функций и констант
</link>».
</simpara>
</listitem>
<listitem>
<simpara>
Полное имя, или имя класса с префиксами наподобие
<literal>$a = new subnamespace\foo();</literal> или
<literal>subnamespace\foo::staticmethod();</literal>. Если текущее пространство имён —
<literal>currentnamespace</literal>, то это имя разрешится
в <literal>currentnamespace\subnamespace\foo</literal>. В коде в глобальном
пространстве имён имя разрешится в <literal>subnamespace\foo</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Абсолютное имя, или имя с префиксом в начале,
который указывает на глобальное пространство имён наподобие
<literal>$a = new \currentnamespace\foo();</literal> или
<literal>\currentnamespace\foo::staticmethod();</literal>. Такое имя разрешается
в буквальное имя, заданное в коде: <literal>currentnamespace\foo</literal>.
</simpara>
</listitem>
</orderedlist>
</para>
<para>
Вот пример трёх видов синтаксиса в реальном коде:
<informalexample>
<simpara>file1.php</simpara>
<programlisting role="php">
<![CDATA[
<?php
namespace Foo\Bar\subnamespace;
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>
]]>
</programlisting>
<simpara>file2.php</simpara>
<programlisting role="php">
<![CDATA[
<?php
namespace Foo\Bar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* Неполные имена */
foo(); // Разрешается в функцию Foo\Bar\foo
foo::staticmethod(); // Разрешается в метод staticmethod класса Foo\Bar\foo
echo FOO; // Разрешается в константу Foo\Bar\FOO
/* Полные имена */
subnamespace\foo(); // Разрешается в функцию Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // Разрешается в метод staticmethod класса Foo\Bar\subnamespace\foo
echo subnamespace\FOO; // Разрешается в константу Foo\Bar\subnamespace\FOO
/* Абсолютные имена */
\Foo\Bar\foo(); // Разрешается в функцию Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // Разрешается в метод staticmethod класса Foo\Bar\foo
echo \Foo\Bar\FOO; // Разрешается в константу Foo\Bar\FOO
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Обратите внимание, что для доступа к глобальным
классам, функциям или константам разрешается указывать абсолютное имя, например,
<function>\strlen</function>, <classname>\Exception</classname>
или \<constant>INI_ALL</constant>.
<example>
<title>Доступ к глобальным классам, функциям и константам из пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Foo;
function strlen() {}
const INI_ALL = 3;
class Exception {}
$a = \strlen('hi'); // Вызывает глобальную функцию strlen
$b = \INI_ALL; // Получает доступ к глобальной константе INI_ALL
$c = new \Exception('error'); // Создаёт экземпляр глобального класса Exception
?>
]]>
</programlisting>
</example>
</para>
</sect1>
<sect1 xml:id="language.namespaces.dynamic">
<title>Пространства имён и динамические особенности языка</title>
<titleabbrev>Пространства имён и динамические особенности языка</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
На реализацию пространств имён в PHP повлияли и динамические свойства языка.
Поэтому, чтобы преобразовать код наподобие следующего примера в код,
который будет работать внутри пространства имён:…
<example>
<title>Динамически доступные элементы</title>
<simpara>example1.php:</simpara>
<programlisting role="php">
<![CDATA[
<?php
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "global";
$a = 'classname';
$obj = new $a; // Выводит classname::__construct
$b = 'funcname';
$b(); // Выводит funcname
echo constant('constname'), "\n"; // Выводит global
?>
]]>
</programlisting>
</example>
…нужно указать абсолютное имя (имя класса с префиксом пространства имён).
Обратите внимание, поскольку между полным и абсолютным именем
внутри динамического имени класса, функции или константы нет разницы,
начальный обратный слеш не нужен.
<example>
<title>Динамически доступные элементы пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace namespacename;
class classname
{
function __construct()
{
echo __METHOD__,"\n";
}
}
function funcname()
{
echo __FUNCTION__,"\n";
}
const constname = "namespaced";
include 'example1.php';
$a = 'classname';
$obj = new $a; // Выводит classname::__construct
$b = 'funcname';
$b(); // Выводит funcname
echo constant('constname'), "\n"; // Выводит global
/* Обратите внимание, что в двойных кавычках символ обратного слеша нужно заэкранировать. Например, "\\namespacename\\classname" */
$a = '\namespacename\classname';
$obj = new $a; // Выводит namespacename\classname::__construct
$a = 'namespacename\classname';
$obj = new $a; // Тоже выводит namespacename\classname::__construct
$b = 'namespacename\funcname';
$b(); // Выводит namespacename\funcname
$b = '\namespacename\funcname';
$b(); // Тоже выводит namespacename\funcname
echo constant('\namespacename\constname'), "\n"; // Выводит namespaced
echo constant('namespacename\constname'), "\n"; // Тоже выводит namespaced
?>
]]>
</programlisting>
</example>
</para>
<para>
Обязательно прочитайте <link linkend="language.namespaces.faq.quote">примечание об
экранировании имён пространства имён в строках</link>.
</para>
</sect1>
<sect1 xml:id="language.namespaces.nsconstants">
<title>Ключевое слово namespace и магическая константа __NAMESPACE__</title>
<titleabbrev>Ключевое слово namespace и константа __NAMESPACE__</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
PHP поддерживает два способа абстрактного доступа к элементам в текущем пространстве
имён: магическая константа <constant>__NAMESPACE__</constant> и ключевое
слово <literal>namespace</literal>.
</para>
<para>
Значение константы <constant>__NAMESPACE__</constant> — это строка, которая содержит
имя текущего пространства имён. В глобальном пространстве, вне пространства имён, она
содержит пустую строку.
<example>
<title>Пример записи константы __NAMESPACE__ в коде с пространством имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject;
echo '"', __NAMESPACE__, '"'; // Выводит «MyProject»
?>
]]>
</programlisting>
</example>
<example>
<title>Пример записи константы __NAMESPACE__ в глобальном пространстве</title>
<programlisting role="php">
<![CDATA[
<?php
echo '"', __NAMESPACE__, '"'; // Выводит «»
?>
]]>
</programlisting>
</example>
Константа <constant>__NAMESPACE__</constant> полезна для динамически конструируемых
имён, например:
<example>
<title>Константа __NAMESPACE__ и динамическое конструирование имени</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject;
function get($classname)
{
$a = __NAMESPACE__ . '\\' . $classname;
return new $a;
}
?>
]]>
</programlisting>
</example>
</para>
<para>
Ключевое слово <literal>namespace</literal> разрешено указывать
для явного запроса элемента из текущего пространства имён или из подпространства.
Это эквивалент ключевого слова <literal>self</literal> для классов в пространстве имён.
<example>
<title>Ключевое слово namespace внутри пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace MyProject;
use blah\blah as mine; // Смотрите «Пространства имён: псевдонимирование и импорт»
blah\mine(); // Вызывает функцию MyProject\blah\mine()
namespace\blah\mine(); // Вызывает функцию MyProject\blah\mine()
namespace\func(); // Вызывает функцию MyProject\func()
namespace\sub\func(); // Вызывает функцию MyProject\sub\func()
namespace\cname::method(); // Вызывает статический метод method класса MyProject\cname
$a = new namespace\sub\cname(); // Создаёт экземпляр класса MyProject\sub\cname
$b = namespace\CONSTANT; // Присваивает значение константы MyProject\CONSTANT переменной $b
?>
]]>
</programlisting>
</example>
<example>
<title>Ключевое слово namespace в глобальном коде</title>
<programlisting role="php">
<![CDATA[
<?php
namespace\func(); // Вызывает функцию func()
namespace\sub\func(); // Вызывает функцию sub\func()
namespace\cname::method(); // Вызывает статический метод method класса cname
$a = new namespace\sub\cname(); // Создаёт экземпляр класса sub\cname
$b = namespace\CONSTANT; // Присваивает значение константы CONSTANT переменной $b
?>
]]>
</programlisting>
</example>
</para>
</sect1>
<sect1 xml:id="language.namespaces.importing">
<title>Пространства имён: псевдонимирование и импорт</title>
<titleabbrev>Псевдонимирование и импорт</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Способность ссылаться на внешнее абсолютное имя по псевдониму
или импортировать внешние абсолютные имена —
это важное свойство пространств имён. Это похоже на способность
файловых систем на основе Unix создавать символические ссылки на файл или директорию.
</para>
<para>
PHP умеет создавать псевдонимы или импортировать константы,
функции, классы, интерфейсы, трейты, перечисления и пространства имён.
</para>
<para>
Псевдоним имени создают через ключевое слово <literal>use</literal>.
Вот пример, который показывает 5 типов импорта:
<example>
<title>Импорт или псевдонимирование через ключевое слово use</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
use My\Full\Classname as Another;
// Это то же, что и My\Full\NSname as NSname
use My\Full\NSname;
// Импортирование глобального класса
use ArrayObject;
// Импортирование функции
use function My\Full\functionName;
// Создание псевдонима функции
use function My\Full\functionName as func;
// Импортирование константы
use const My\Full\CONSTANT;
$obj = new namespace\Another; // Создаёт экземпляр класса foo\Another
$obj = new Another; // Создаёт объект класса My\Full\Classname
NSname\subns\func(); // Вызывает функцию My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // Создаёт объект класса ArrayObject
// без выражения use ArrayObject был бы создан объект класса foo\ArrayObject
func(); // вызывает функцию My\Full\functionName
echo CONSTANT; // выводит содержимое константы My\Full\CONSTANT
?>
]]>
</programlisting>
</example>
Обратите внимание, что именам внутри пространства имён (абсолютным именам пространств имён,
которые содержат разделитель пространств имён, например <literal>Foo\Bar</literal>,
в отличие от глобальных имён, которые его не содержат, например <literal>FooBar</literal>)
начальный обратный слеш (\) не нужен и не рекомендован,
поскольку импортируемые имена должны быть абсолютными и не обрабатываются
относительно текущего пространства имён.
</para>
<para>
PHP дополнительно поддерживает удобное сокращение для задания нескольких операторов
use в одной и той же строке
<example>
<title>Импорт или создание псевдонима через ключевое слово use, комбинирование нескольких выражений</title>
<programlisting role="php">
<![CDATA[
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // Создаёт объект класса My\Full\Classname
NSname\subns\func(); // Вызывает функцию My\Full\NSname\subns\func
?>
]]>
</programlisting>
</example>
</para>
<para>
Импорт выполняется во время компиляции поэтому не влияет на имена динамических классов,
функций или констант.
<example>
<title>Импорт и динамические имена</title>
<programlisting role="php">
<![CDATA[
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // Создаёт объект класса My\Full\Classname
$a = 'Another';
$obj = new $a; // Создаёт объект класса Another
?>
]]>
</programlisting>
</example>
</para>
<para>
В дополнение, импорт распространяется только на неполные и полные имена. На абсолютные
имена операция импорта не влияет.
<example>
<title>Импортирование и абсолютные имена</title>
<programlisting role="php">
<![CDATA[
<?php
use My\Full\Classname as Another, My\Full\NSname;
$obj = new Another; // Создаёт объект класса My\Full\Classname
$obj = new \Another; // Создаёт объект класса Another
$obj = new Another\thing; // Создаёт объект класса My\Full\Classname\thing
$obj = new \Another\thing; // Создаёт объект класса Another\thing
?>
]]>
</programlisting>
</example>
</para>
<sect2 xml:id="language.namespaces.importing.scope">
<title>Обзор правил для импорта</title>
<para>
Ключевое слово <literal>use</literal> должно быть указано в самом начале файла (в
глобальной области) или внутри объявления пространства имён. Это нужно, потому что
импорт выполняется во время компиляции, а не во время исполнения, поэтому его
нельзя ограничить блоком кода. Следующий пример показывает недопустимое указание
ключевого слова <literal>use</literal>:
</para>
<para>
<example>
<title>Недопустимое правило импорта</title>
<programlisting role="php">
<![CDATA[
<?php
namespace Languages;
function toGreenlandic()
{
use Languages\Danish;
//...
}
?>
]]>
</programlisting>
</example>
</para>
<note>
<para>
Правила импорта задают на каждый файл отдельно. Поэтому
присоединяемые файлы <emphasis>НЕ</emphasis> будут наследовать правила импорта
из родительского файла.
</para>
</note>
</sect2>
<sect2 xml:id="language.namespaces.importing.group">
<title>Групповые объявления через ключевое слово <literal>use</literal></title>
<para>
Классы, функции и константы, импортируемые из одного и того же
пространства имён (&namespace;), разрешено группировать в одном
выражении с ключевым словом &use.namespace;.
</para>
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;
use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;
use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;
// Эквивалентно следующему групповому объявлению с ключевым словом use
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};
]]>
</programlisting>
</informalexample>
</sect2>
</sect1>
<sect1 xml:id="language.namespaces.global">
<title>Глобальное пространство</title>
<titleabbrev>Глобальное пространство</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Без определения пространства имён определения классов и функций
помещаются в глобальном пространстве — так же, как это было в PHP до введения
пространств имён. Добавление префикса <literal>\</literal> к именам указывает, что
требуется имя из глобального пространства, даже в контексте пространства имён.
<example>
<title>Спецификация глобального пространства</title>
<programlisting role="php">
<![CDATA[
<?php
namespace A\B\C;
/* Функция — это A\B\C\fopen */
function fopen() {
/* ... */
$f = \fopen(...); // Вызов глобальной функции fopen
return $f;
}
?>
]]>
</programlisting>
</example>
</para>
</sect1>
<sect1 xml:id="language.namespaces.fallback">
<title>Пространства имён: возврат к глобальному пространству для функций и констант</title>
<titleabbrev>Возврат к глобальному пространству</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Когда внутри пространства имён PHP встречает неполное имя класса, функции или
контекст константы, он разрешает эти имена с разными приоритетами. Имена классов
разрешаются в текущее имя пространства имён. Поэтому, чтобы получить доступ
ко внутреннему классу или пользовательскому классу вне пространства имён, необходимо
обращаться к ним по абсолютному имени. Например:
<example>
<title>Доступ к глобальным классам внутри пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace A\B\C;
class Exception extends \Exception {}
$a = new Exception('hi'); // Переменная $a — это объект класса A\B\C\Exception
$b = new \Exception('hi'); // Переменная $b — это объект класса Exception
$c = new ArrayObject; // Фатальная ошибка, класс A\B\C\ArrayObject не найден
?>
]]>
</programlisting>
</example>
</para>
<para>
PHP будет обращаться к глобальным функциям или константам,
если функция или константа не существует в текущем пространстве имён.
<example>
<title>Возврат к глобальным функциям или константам внутри пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace A\B\C;
const E_ERROR = 45;
function strlen($str)
{
return \strlen($str) - 1;
}
echo E_ERROR, "\n"; // Выводит 45
echo INI_ALL, "\n"; // Выводит «7» — возвращается к глобальной константе INI_ALL
echo strlen('hi'), "\n"; // Выводит «1»
if (is_array('hi')) { // Выводит строку «это не массив»
echo "Это массив\n";
} else {
echo "Это не массив\n";
}
?>
]]>
</programlisting>
</example>
</para>
</sect1>
<sect1 xml:id="language.namespaces.rules">
<title>Правила разрешения имён</title>
<titleabbrev>Правила разрешения имён</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Для целей этих правил разрешения приведём важные определения:
<variablelist>
<title>Определения имени пространства имён</title>
<varlistentry>
<term>Неполное имя</term>
<listitem>
<para>
Идентификатор без разделителя пространств имён, например <literal>Foo</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Полное имя</term>
<listitem>
<para>
Идентификатор с разделителем пространств имён, например <literal>Foo\Bar</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Абсолютное имя</term>
<listitem>
<para>
Идентификатор с разделителем пространств имён, который начинается с разделителя пространств имён,
например <literal>\Foo\Bar</literal>. Пространство имён <literal>\Foo</literal>
также абсолютное имя.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Относительное имя</term>
<listitem>
<para>
Идентификатор, который начинается с ключевого слова <literal>namespace</literal>,
например <literal>namespace\Foo\Bar</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
Имена разрешаются по следующим правилам:
<orderedlist>
<listitem>
<simpara>
Абсолютные имена разрешаются в имя без ведущего разделителя пространства имён.
Например, <literal>\A\B</literal> разрешается в <literal>A\B</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Относительные имена разрешаются в имя с заменой ключевого слова <literal>namespace</literal>
текущим пространством имён. Если имя встречается в глобальном пространстве имён,
префикс <literal>namespace\</literal> удаляется. Например,
имя <literal>namespace\A</literal> внутри пространства имён <literal>X\Y</literal> разрешается
в <literal>X\Y\A</literal>. То же имя в глобальном пространстве имён разрешается
в <literal>A</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
В полных именах первый сегмент имени преобразовывается с учётом текущей таблицы
импорта класса или пространства имён. Например, если пространство имён <literal>A\B\C</literal>
импортировано как <literal>C</literal>, то имя <literal>C\D\E</literal> преобразуется
в <literal>A\B\C\D\E</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
В полных именах, если не применялось правило импорта, текущее пространство имён добавляется к имени.
Например, имя <literal>C\D\E</literal> внутри пространства имён <literal>A\B</literal>
разрешится в <literal>A\B\C\D\E</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
Неполные имена преобразовываются с учётом текущей таблицы импорта
и типа элемента. То есть имена как у классов преобразовываются с учётом таблицы импорта классов или пространств имён,
имена функций — с учётом таблицы импорта функций, а константы — таблицы импорта
констант. Например, при записи <literal>use A\B\C;</literal>, вызов <literal>new C()
</literal> разрешается в <literal>A\B\C()</literal>. Аналогично, при
записи <literal>use function A\B\foo;</literal> вызов <literal>foo()</literal> разрешается
в <literal>A\B\foo</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
В начало неполных имён, если не применялось правило импорта и имя относится к элементу
с именем как у класса, добавляется текущее пространство имён. Например,
имя класса в выражении <literal>new C()</literal> внутри пространства имён <literal>A\B</literal> разрешится
в имя <literal>A\B\C</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
В неполных именах, если не применялось правило импорта и имя относится к функции или константе,
а код лежит за пределами глобального пространства имён,
имя разрешается при выполнении. Вот как разрешится вызов функции <literal>foo()</literal>
в коде в пространстве имён <literal>A\B</literal>:
</simpara>
<orderedlist>
<listitem>
<simpara>
Выполняется поиск функции из текущего пространства имён:
<literal>A\B\foo()</literal>.
</simpara>
</listitem>
<listitem>
<simpara>
PHP пытается найти и вызвать функцию <literal>foo()</literal>
из <emphasis>глобального пространства имён</emphasis>.
</simpara>
</listitem>
</orderedlist>
</listitem>
</orderedlist>
</para>
<example>
<title>Примеры разрешения имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace A;
use B\D, C\E as F;
// вызовы функций
foo(); // Сперва пытается вызвать функцию foo, определённую в пространстве имён A,
// Затем вызывает глобальную функцию foo
\foo(); // Вызывает функцию foo, определённую в глобальном пространстве
my\foo(); // Вызывает функцию foo, определённую в пространстве имён A\my
F(); // Сперва пытается вызвать функцию F, определённую в пространстве имён A,
// Затем вызывает глобальную функцию F
// Ссылки на классы
new B(); // Создаёт объект класса B, определённого в пространстве имён A.
// Если класс не найден, то пытается сделать автозагрузку класса A\B
new D(); // Используя правила импорта, создаёт объект класса D, определённого в пространстве имён B,
// если класс не найден, то пытается сделать автозагрузку класса B\D
new F(); // Используя правила импорта, создаёт объект класса E, определённого в пространстве имён C,
// если класс не найден, то пытается сделать автозагрузку класса C\E
new \B(); // Создаёт объект класса B, определённого в глобальном пространстве,
// если класс не найден, то пытается сделать автозагрузку класса B
new \D(); // Создаёт объект класса D, определённого в глобальном пространстве,
// если класс не найден, то пытается сделать автозагрузку класса D
new \F(); // Создаёт объект класса F, определённого в глобальном пространстве,
// если класс не найден, то пытается сделать автозагрузку класса F
// Статические методы и функции пространства имён из другого пространства имён
B\foo(); // Вызывает функцию foo из пространства имён A\B
B::foo(); // Вызывает метод foo из класса B, определённого в пространстве имён A,
// если класс A\B не найден, то пытается сделать автозагрузку класса A\B
D::foo(); // Используя правила импорта, вызывает метод foo класса D, определённого в пространстве имён B,
// если класс B\D не найден, то пытается сделать автозагрузку класса B\D
\B\foo(); // Вызывает функцию foo из пространства имён B
\B::foo(); // Вызывает метод foo класса B из глобального пространства,
// если класс B не найден, то пытается сделать автозагрузку класса B
// Статические методы и функции пространства имён из текущего пространства имён
A\B::foo(); // Вызывает метод foo класса B из пространства имён A\A,
// если класс A\A\B не найден, то пытается сделать автозагрузку класса A\A\B
\A\B::foo(); // Вызывает метод foo класса B из пространства имён A,
// если класс A\B не найден, то пытается сделать автозагрузку класса A\B
?>
]]>
</programlisting>
</example>
</sect1>
<sect1 xml:id="language.namespaces.faq">
<title>Часто задаваемые вопросы (FAQ): что нужно знать о пространствах имён</title>
<titleabbrev>FAQ</titleabbrev>
<?phpdoc print-version-for="namespaces"?>
<para>
Этот список вопросов разделён на две части: общие вопросы и некоторые особенности
реализации, которые полезны для полного понимания.
</para>
<para>
Вначале общие вопросы.
<orderedlist>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.shouldicare">Если в коде не указаны пространства имён, нужно
ли считать что-либо из этого важным?</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.globalclass">Как обращаться к внутренним или глобальным
классам в пространстве имён?</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.innamespace">Как обращаться к функциям классов в
пространствах имён, или константам в их пространстве имён?</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.full">
Как разрешаются имена <literal>\my\name</literal> или <literal>\name</literal>?
</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.qualified">Как разрешается имя <literal>my\name</literal>?</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.shortname1">Как разрешается неполное имя класса <literal>name</literal>?</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.shortname2">Как разрешается неполное имя функции
или неполное имя константы наподобие <literal>name</literal>?</link>
</simpara>
</listitem>
</orderedlist>
</para>
<para>
Некоторые детали реализации пространств имён, которые
полезно понимать.
<orderedlist>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.conflict">Импортируемые имена не должны конфликтовать с
классами, определёнными в том же файле.</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.nested">Вложенные пространства имён недопустимы.
</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.quote">Динамические имена пространств имён (идентификаторы,
взятые в кавычки) должны экранировать символ обратного слеша.</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.constants">Ссылаться на неопределённые константы,
используя обратный слеш, нельзя. Выводится фатальная ошибка</link>
</simpara>
</listitem>
<listitem>
<simpara>
<link linkend="language.namespaces.faq.builtinconst">Невозможно переопределить специальные
константы &null;, &true; или &false;</link>
</simpara>
</listitem>
</orderedlist>
</para>
<sect2 xml:id="language.namespaces.faq.shouldicare">
<title>Если в коде не указаны пространства имён, нужно ли считать что-либо из этого важным?</title>
<para>
Нет, пространства имён не влияют ни на тот код, который уже написали,
ни на ещё ненаписанный код без пространств имён. Разрешается писать
такой код, если нужно:
</para>
<para>
<example>
<title>Доступ к глобальным классам вне пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
$a = new \stdClass;
?>
]]>
</programlisting>
</example>
</para>
<para>
Функционально это эквивалентно следующему:
</para>
<para>
<example>
<title>Доступ к глобальным классам вне пространства имён</title>
<programlisting role="php">
<![CDATA[
<?php
$a = new stdClass;
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.globalclass">
<title>Как обращаться к внутренним или глобальным классам в пространстве имён?</title>
<para>
<example>
<title>Доступ ко внутренним классам в пространствах имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
$a = new \stdClass;
function test(\ArrayObject $parameter_type_example = null) {}
$a = \DirectoryIterator::CURRENT_AS_FILEINFO;
// Расширение внутреннего или глобального класса
class MyException extends \Exception {}
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.innamespace">
<title>
Как использовать функции классов в пространствах имён или
константы в их собственном пространстве имён?
</title>
<para>
<example>
<title>Доступ ко внутренним классам, функциям или константам в пространствах имён</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
class MyClass {}
// Определение класса текущего пространства имён в качестве типа параметра
function test(MyClass $parameter_type_example = null) {}
// Другой способ определить класс из текущего пространства имён в качестве типа параметра
function test(\foo\MyClass $parameter_type_example = null) {}
// Расширение класса из текущего пространства имён
class Extended extends MyClass {}
// Доступ к глобальной функции
$a = \globalfunc();
// Доступ к глобальной константе
$b = \INI_ALL;
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.full">
<title>
Как имена вроде <literal>\my\name</literal> или <literal>\name</literal>
преобразовываются?
</title>
<para>
Имена, которые начинаются с <literal>\</literal>, преобразовываются к тому, как
они выглядят, т. е. <literal>\my\name</literal> — это на самом деле <literal>my\name</literal>,
а <literal>\Exception</literal> — это <literal>Exception</literal>.
<example>
<title>Абсолютные имена</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
$a = new \my\name(); // Создаёт экземпляр класса my\name
echo \strlen('hi'); // Вызывает функцию strlen
$a = \INI_ALL; // Переменной $a присваивается значение константы INI_ALL
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.qualified">
<title>Как имя <literal>my\name</literal> преобразуется?</title>
<para>
Имена, которые содержат обратный слеш, но не начинаются с него, например,
<literal>my\name</literal>, — разрешено преобразовывать двумя способами.
</para>
<para>
Если написано
импортирующее выражение, которое создаёт синоним <literal>my</literal> другого имени,
то этот синоним будет применён к <literal>my</literal> в записи <literal>my\name</literal>.
</para>
<para>
В противном случае текущее имя пространства имён становится префиксом к имени <literal>my\name</literal>.
</para>
<para>
<example>
<title>Полные имена</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
use blah\blah as foo;
$a = new my\name(); // Создаёт экземпляр класса foo\my\name
foo\bar::name(); // Вызывает статический метод name в классе blah\blah\bar
my\bar(); // Вызывает функцию foo\my\bar
$a = my\BAR; // Присваивает переменной $a значение константы foo\my\BAR
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.shortname1">
<title>Как неполное имя класса вроде <literal>name</literal> преобразовывается?</title>
<para>
Имена классов без обратного слеша, например
<literal>name</literal>, могут быть преобразованы двумя способами.
</para>
<para>
Если написано
импортирующее выражение, которое создаёт синоним <literal>name</literal> другого имени, то
будет применён этот синоним.
</para>
<para>
В противном случае текущее имя пространства имён становится префиксом к <literal>name</literal>.
</para>
<para>
<example>
<title>Неполные имена классов</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
use blah\blah as foo;
$a = new name(); // Создаёт экземпляр класса foo\name
foo::name(); // Вызывает статический метод name в классе blah\blah
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.shortname2">
<title>Как неполное имя функции или неполное имя константы, например,
<literal>name</literal> преобразовывается?
</title>
<para>
Имена функций или констант без обратного слеша, например
<literal>name</literal>, могут быть преобразованы двумя способами.
</para>
<para>
Сперва текущее имя пространства имён становится префиксом к <literal>name</literal>.
</para>
<para>
Затем, если константа или функция <literal>name</literal> не существует
в текущем пространстве имён, будет использована глобальная константа
или функция <literal>name</literal>, если она существует.
</para>
<para>
<example>
<title>Неполные имена функций или констант</title>
<programlisting role="php">
<![CDATA[
<?php
namespace foo;
use blah\blah as foo;
const FOO = 1;
function my() {}
function foo() {}
function sort(&$a)
{
\sort($a); // Вызывает глобальную функцию sort
$a = array_flip($a);
return $a;
}
my(); // вызывает foo\my
$a = strlen('hi'); // Вызывает глобальную функцию strlen, потому что foo\strlen не существует
$arr = array(1,3,2);
$b = sort($arr); // Вызывает функцию foo\sort
$c = foo(); // Вызывает функцию foo\foo — импорт не применяется
$a = FOO; // Присваивает переменной $a значение константы «foo\FOO» — импорт не применяется
$b = INI_ALL; // Присваивает переменной $b значение глобальной константы INI_ALL
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.conflict">
<title>Импортируемые имена не должны конфликтовать с классами, определёнными в том же файле.</title>
<para>
Следующие комбинации скриптов допустимы:
<informalexample>
<simpara>file1.php</simpara>
<programlisting role="php">
<![CDATA[
<?php
namespace my\stuff;
class MyClass {}
?>
]]>
</programlisting>
<simpara>another.php</simpara>
<programlisting role="php">
<![CDATA[
<?php
namespace another;
class thing {}
?>
]]>
</programlisting>
<simpara>file2.php</simpara>
<programlisting role="php">
<![CDATA[
<?php
namespace my\stuff;
include 'file1.php';
include 'another.php';
use another\thing as MyClass;
$a = new MyClass; // Создаёт экземпляр класса thing из пространства имён another
?>
]]>
</programlisting>
</informalexample>
</para>
<para>
Конфликт имён отсутствует, даже несмотря на то что класс <literal>MyClass</literal> существует
внутри пространства имён <literal>my\stuff</literal>, потому что определение MyClass
находится в отдельном файле. Однако следующий пример приводит к фатальной ошибке с конфликтом
имён, потому что класс MyClass определён в том же файле, в котором указано ключевое слово use.
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
namespace my\stuff;
use another\thing as MyClass;
class MyClass {} // Фатальная ошибка: MyClass конфликтует с выражением импорта
$a = new MyClass;
?>
]]>
</programlisting>
</informalexample>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.nested">
<title>Вложенные пространства имён недопустимы.</title>
<para>
PHP не разрешает вложение пространств имён
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
namespace my\stuff {
namespace nested {
class foo {}
}
}
?>
]]>
</programlisting>
</informalexample>
Однако сымитировать вложенные пространства имён можно так:
<informalexample>
<programlisting role="php">
<![CDATA[
<?php
namespace my\stuff\nested {
class foo {}
}
?>
]]>
</programlisting>
</informalexample>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.quote">
<title>
Динамические имена пространств имён (идентификаторы, взятые в кавычки)
должны экранировать символ обратного слеша.
</title>
<para>
Важно понимать это, потому что обратный слеш внутри строк работает как экранирующий символ.
Он должен быть продублирован, когда указан внутри строки, иначе
появляется риск неумышленных последствий:
<example>
<title>
Подводные камни при указании имени пространства имён
внутри строки с двойными кавычками
</title>
<programlisting role="php">
<![CDATA[
<?php
$a = "dangerous\name"; // Символ \n — это переход на новую строку внутри строки с двойными кавычками!
$obj = new $a;
$a = 'not\at\all\dangerous'; // А тут нет проблем.
$obj = new $a;
?>
]]>
</programlisting>
</example>
Внутри строк, заключённых в одинарные кавычки, обратный слеш в качестве разделителя более безопасен, но
по-прежнему лучше рекомендуемая практика экранирования обратного слеша во всех строках.
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.constants">
<title>Ссылаться на неопределённые константы, используя обратный слеш, нельзя. Выводится фатальная ошибка</title>
<para>
Любая неопределённая константа — неполное имя наподобие <literal>FOO</literal> — будет
приводить к выводу сообщения о том, что PHP предположил, что <literal>FOO</literal> было значением
константы. Любая константа, с полным или абсолютным именем, которая содержит
символ обратного слеша, будет приводить к фатальной ошибке, если не будет найдена.
<example>
<title>Неопределённые константы</title>
<programlisting role="php">
<![CDATA[
<?php
namespace bar;
$a = FOO; // Выводит предупреждение: undefined constants "FOO" assumed "FOO";
$a = \FOO; // Фатальная ошибка: undefined namespace constant FOO
$a = Bar\FOO; // Фатальная ошибка: undefined namespace constant bar\Bar\FOO
$a = \Bar\FOO; // Фатальная ошибка: undefined namespace constant Bar\FOO
?>
]]>
</programlisting>
</example>
</para>
</sect2>
<sect2 xml:id="language.namespaces.faq.builtinconst">
<title>Невозможно переопределить специальные константы &null;, &true; или &false;</title>
<para>
Любая попытка определить константу пространства имён,
которая совпадает с названиями специальных встроенных констант,
приведёт к фатальной ошибке.
<example>
<title>Неопределённые константы</title>
<programlisting role="php">
<![CDATA[
<?php
namespace bar;
const NULL = 0; // Фатальная ошибка;
const true = 'stupid'; // Тоже фатальная ошибка;
// и т. д.
?>
]]>
</programlisting>
</example>
</para>
</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
-->