(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
?>
Следующие комбинации скриптов допустимы:
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'; // Тоже фатальная ошибка;
// и т. д.
?>