(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'; // Тоже фатальная ошибка;
// и т. д.
?>