(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\name
заменяется псевдонимом,
если уровню my
присвоили псевдоним с другим именем, которое импортировали инструкцией use.
В остальных случаях перед именем 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
присвоили псевдоним с другим именем, которое импортировали инструкцией use.
В остальных случаях к имени 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 = [1, 3, 2,];
$b = sort($arr); // Вызывает функцию foo\sort
$c = foo(); // Вызывает функцию foo\foo, без импорта
$a = FOO; // Присваивает переменной $a значение константы foo\FOO, без импорта
$b = INI_ALL; // Присваивает переменной $b значение глобальной константы INI_ALL
?>
Следующие комбинации скриптов допустимы:
file1.php
<?php
namespace my\stuff;
class MyClass {}
?>
another.php
<?php
namespace another;
class thing {}
?>
file2.php
<?php
namespace my\stuff;
include 'file1.php';
include 'another.php';
use another\thing as MyClass;
$a = new MyClass; // Создаёт экземпляр класса thing из пространства имён another
?>
Конфликт имён отсутствует, даже несмотря на то что класс MyClass
существует
внутри пространства имён my\stuff
, потому что определение MyClass
находится в отдельном файле. Однако следующий пример приводит к фатальной ошибке с конфликтом
имён, потому что класс MyClass определён в том же файле, в котором указано ключевое слово use.
<?php
namespace my\stuff;
use another\thing as MyClass;
class MyClass {} // Фатальная ошибка: MyClass конфликтует с выражением импорта
$a = new MyClass();
?>
PHP не разрешает вложение пространств имён
<?php
namespace my\stuff {
namespace nested {
class foo {}
}
}
?>
<?php
namespace my\stuff\nested {
class foo {}
}
?>
Важно понимать это, потому что обратный слеш внутри строк работает как экранирующий символ. Он должен быть продублирован, когда указан внутри строки, иначе появляется риск неумышленных последствий:
Пример #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'; // Тоже фатальная ошибка;
// и т. д.
?>