(PHP 5 >= 5.3.0, PHP 7)
Этот список вопросов разделен на две части: общие вопросы и некоторые особенности реализации, которые полезны для более полного понимания.
Сперва, общие вопросы.
Некоторые детали реализации пространств имен, которые полезно понимать.
Нет. Пространства имен не оказывают никакого влияния ни на какой существующий код ни в каком виде или на любой написанный код, который не содержит пространств имен. Вы можете написать такой код, если желаете:
Пример #1 Доступ к глобальным классам вне пространства имен
<?php
$a = new \stdClass;
?>
Это функционально эквивалентно следующему:
Пример #2 Доступ к глобальным классам вне пространства имен
<?php
$a = new stdClass;
?>
Пример #3 Доступ ко внутренним классам в пространствах имен
<?php
namespace foo;
$a = new \stdClass;
function test(\ArrayObject $typehintexample = null) {}
$a = \DirectoryIterator::CURRENT_AS_FILEINFO;
// расширение внутреннего или глобального класса
class MyException extends \Exception {}
?>
Пример #4 Доступ ко внутренним классам, функциям или константам в пространствах имен
<?php
namespace foo;
class MyClass {}
// использование класса из текущего пространства имен
function test(MyClass $typehintexample = null) {}
// другой способ использовать класс из текущего пространства имен
function test(\foo\MyClass $typehintexample = null) {}
// расширение класса из текущего пространства имен
class Extended extends MyClass {}
// доступ к глобальной функции
$a = \globalfunc();
// доступ к глобальной константе
$b = \INI_ALL;
?>
Имена, которые начинаются с \ всегда преобразуются к тому как они выглядят, т.е. \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 другого имени, то этот синоним применяется к 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 другого имени, то применяется этот синоним.
В ином случае, текущее имя пространства имен становится префиксом к my\name.
Пример #7 Неполные имена классов
<?php
namespace foo;
use blah\blah as foo;
$a = new name(); // создает экземпляр класса "foo\name"
foo::name(); // вызывает статический метод "name" в классе "blah\blah"
?>
Имена функций или констант, которые не содержат обратного слеша, такие как 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 {}
}
?>
Элементы, которые подвержены действию оператора use - это пространства имен и имена классов. Для сокращения длинных имен констант или функций, заимпортируйте их содержимое в пространство имен.
<?php
namespace mine;
use ultra\long\ns\name;
$a = name\CONSTANT;
name\func();
?>
Очень важно представлять это, потому что обратный слеш используется как экранирующий символ внутри строк. Он всегда должен быть продублирован, когда используется внутри строки, иначе появляется риск возникновения неумышленных последствий:
Пример #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
?>
Любая попытка определить константу пространства имен, которая совпадает с названиями специальных встроенных констант, приведет к фатальной ошибке.
Пример #11 Неопределенные константы
<?php
namespace bar;
const NULL = 0; // Фатальная ошибка;
const true = 'stupid'; // также фатальная ошибка;
// и т.д.
?>