1
0
mirror of https://github.com/php/doc-ru.git synced 2026-03-24 07:42:22 +01:00
Files
archived-doc-ru/language/namespaces.xml
2026-01-04 07:46:04 +03:00

1611 lines
70 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 1651836ff309efd14a795eff44ee51455f66c7d3 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; // Фатальная ошибка, поскольку объявление пространства имён идёт не первой инструкцией в скрипте
]]>
</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\name</literal> заменяется псевдонимом,
если уровню <literal>my</literal> присвоили псевдоним с другим именем, которое импортировали инструкцией use.
</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> присвоили псевдоним с другим именем, которое импортировали инструкцией use.
</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 = [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
-->