Часто задаваемые вопросы (FAQ): что нужно знать о пространствах имён
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
Этот список вопросов разделён на две части: общие вопросы и некоторые особенности
реализации, которые полезны для полного понимания.
Вначале общие вопросы.
-
Если в коде не указаны пространства имён, нужно
ли считать что-либо из этого важным?
-
Как обращаться к внутренним или глобальным
классам в пространстве имён?
-
Как обращаться к функциям классов в
пространствах имён, или константам в их пространстве имён?
-
Как разрешаются имена
\my\name
или \name
?
-
Как разрешается имя
my\name
?
-
Как разрешается неполное имя класса
name
?
-
Как разрешается неполное имя функции
или неполное имя константы наподобие
name
?
Некоторые детали реализации пространств имён, которые
полезно понимать.
-
Импортируемые имена не должны конфликтовать с
классами, определёнными в том же файле.
-
Вложенные пространства имён недопустимы.
-
Динамические имена пространств имён (идентификаторы,
взятые в кавычки) должны экранировать символ обратного слеша.
-
Ссылаться на неопределённые константы,
используя обратный слеш, нельзя. Выводится фатальная ошибка
-
Невозможно переопределить специальные
константы
null
, true
или false
Если в коде не указаны пространства имён, нужно ли считать что-либо из этого важным?
Нет, пространства имён не влияют ни на тот код, который уже написали,
ни на ещё ненаписанный код без пространств имён. Разрешается писать
такой код, если нужно:
Пример #1 Доступ к глобальным классам вне пространства имён
<?php
$a = new \stdClass;
?>
Функционально это эквивалентно следующему:
Пример #2 Доступ к глобальным классам вне пространства имён
<?php
$a = new stdClass;
?>
Как обращаться к внутренним или глобальным классам в пространстве имён?
Пример #3 Доступ ко внутренним классам в пространствах имён
<?php
namespace foo;
$a = new \stdClass;
function test(\ArrayObject $parameter_type_example = null) {}
$a = \DirectoryIterator::CURRENT_AS_FILEINFO;
// Расширение внутреннего или глобального класса
class MyException extends \Exception {}
?>
Как использовать функции классов в пространствах имён или
константы в их собственном пространстве имён?
Пример #4 Доступ ко внутренним классам, функциям или константам в пространствах имён
<?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;
?>
Как имена вроде \my\name
или \name
преобразовываются?
Имена, которые начинаются с \
, преобразовываются к тому, как
они выглядят, т. е. \my\name
— это на самом деле my\name
,
а \Exception
— это Exception
.
Пример #5 Абсолютные имена
<?php
namespace foo;
$a = new \my\name(); // Создаёт экземпляр класса my\name
echo \strlen('hi'); // Вызывает функцию strlen
$a = \INI_ALL; // Переменной $a присваивается значение константы INI_ALL
?>
Как имя my\name
преобразуется?
Имена, которые содержат обратный слеш, но не начинаются с него, например,
my\name
, — разрешено преобразовывать двумя способами.
Если написано
импортирующее выражение, которое создаёт синоним my
другого имени,
то этот синоним будет применён к my
в записи my\name
.
В противном случае текущее имя пространства имён становится префиксом к имени my\name
.
Пример #6 Полные имена
<?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
?>
Как неполное имя класса вроде name
преобразовывается?
Имена классов без обратного слеша, например
name
, могут быть преобразованы двумя способами.
Если написано
импортирующее выражение, которое создаёт синоним name
другого имени, то
будет применён этот синоним.
В противном случае текущее имя пространства имён становится префиксом к name
.
Пример #7 Неполные имена классов
<?php
namespace foo;
use blah\blah as foo;
$a = new name(); // Создаёт экземпляр класса foo\name
foo::name(); // Вызывает статический метод name в классе blah\blah
?>
Как неполное имя функции или неполное имя константы, например,
name
преобразовывается?
Имена функций или констант без обратного слеша, например
name
, могут быть преобразованы двумя способами.
Сперва текущее имя пространства имён становится префиксом к name
.
Затем, если константа или функция name
не существует
в текущем пространстве имён, будет использована глобальная константа
или функция name
, если она существует.
Пример #8 Неполные имена функций или констант
<?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
?>
Импортируемые имена не должны конфликтовать с классами, определёнными в том же файле.
Следующие комбинации скриптов допустимы:
Конфликт имён отсутствует, даже несмотря на то что класс MyClass
существует
внутри пространства имён my\stuff
, потому что определение MyClass
находится в отдельном файле. Однако следующий пример приводит к фатальной ошибке с конфликтом
имён, потому что класс MyClass определён в том же файле, в котором указано ключевое слово use.
Вложенные пространства имён недопустимы.
PHP не разрешает вложение пространств имён
Однако сымитировать вложенные пространства имён можно так:
Динамические имена пространств имён (идентификаторы, взятые в кавычки)
должны экранировать символ обратного слеша.
Важно понимать это, потому что обратный слеш внутри строк работает как экранирующий символ.
Он должен быть продублирован, когда указан внутри строки, иначе
появляется риск неумышленных последствий:
Пример #9
Подводные камни при указании имени пространства имён
внутри строки с двойными кавычками
<?php
$a = "dangerous\name"; // Символ \n — это переход на новую строку внутри строки с двойными кавычками!
$obj = new $a;
$a = 'not\at\all\dangerous'; // А тут нет проблем.
$obj = new $a;
?>
Внутри строк, заключённых в одинарные кавычки, обратный слеш в качестве разделителя более безопасен, но
по-прежнему лучше рекомендуемая практика экранирования обратного слеша во всех строках.
Ссылаться на неопределённые константы, используя обратный слеш, нельзя. Выводится фатальная ошибка
Любая неопределённая константа — неполное имя наподобие FOO
— будет
приводить к выводу сообщения о том, что PHP предположил, что FOO
было значением
константы. Любая константа, с полным или абсолютным именем, которая содержит
символ обратного слеша, будет приводить к фатальной ошибке, если не будет найдена.
Пример #10 Неопределённые константы
<?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
?>
Невозможно переопределить специальные константы null
, true
или false
Любая попытка определить константу пространства имён,
которая совпадает с названиями специальных встроенных констант,
приведёт к фатальной ошибке.
Пример #11 Неопределённые константы
<?php
namespace bar;
const NULL = 0; // Фатальная ошибка;
const true = 'stupid'; // Тоже фатальная ошибка;
// и т. д.
?>