Продолжаем знакомиться с пространствами имен. В предыдущей статье мы узнали, что такое пространства имен, зачем они нужны, узнали что инклюдить файлы все равно придется, и рассмотрели пример о том, как же ими пользоваться, как определять и т.д.

В этой статье рассмотрим остальные аспекты пространств имен, которые не были затронуты ранее.

Глобальное пространство имен

В конце прошлой статьи я говорил об относительности путей подключения пространств имен и сравнивал их с директориями в операционке. Так вот, как и в UNIX системах, например, есть корневой элемент. Адрес корня сервера имеет вид - /
Аналогично этому существует корневое пространство имен - \
Все стандартные функции языка, все ваши классы и функции, константы, описанные без привязки к пространству имен, на самом деле будут принадлежать глобальному пространству имен.
Если вы определили функцию вне пространства имен, то обратиться к ней можно будет двумя способами:

function foo()
{
   return 'Абсолютно бесполезная функция';
}

echo foo();    // = Абсолютно бесполезная функция
echo \foo();   // = Абсолютно бесполезная функция

Поэтому вы всегда можете быть уверенными, что если вы вызываете функцию \print_r() - это будет всегда функция, встроенная в php.
Да да - вы не ослышались - внутри своего пространства имен можно определить функцию, которая будет иметь название, аналогичное встроенной функции. Вот пример:

namespace Space;
function print_r($s)
{
   echo $s . ' - а вот и не print_r :Р';
}

$toPrint = 'На печать';
print_r($toPrint);     // = На печать - а вот и не print_r :Р
\print_r($toPrint);    // = На печать

Поэтому - не стоит бездумно переопределять встроенные функции, т.к. это может ввести в заблуждение неопытных разработчиков.

Ну и будьте благоразумны при построении пути из неймспейсов при разработке. Если в вашем файле определено пространство имен, то все вызовы будут строиться от текущего пространства имен. Находясь в namespace Space вы должны осознавать, что вызов функции без префикса из пространств имен приведет к вызову функции из текущего пространства, а если вы вызываете функцию с пространством имен, то либо пространство должно быть относительным от текущего, либо должно начинаться с глобального

namespace Universe;
function wow()
{
   echo 'Universe';
}

namespace Universe\Galaxy;
function wow()
{
   echo 'Universe\Galaxy';
}

wow();                   // = Universe\Galaxy
\Universe\Galaxy\wow();  // = Universe\Galaxy
Universe\Galaxy\wow();   // = Fatal Error
\Universe\wow();         // = Universe

Таким образом какой вывод можно сделать из того, что мы уже изучили - то что пространство имен является частью имени сущности php. Эти самые имена теперь делятся на 3 вида:

  1. Неполные имена. Это привычные нам имена без пространств имен. Например - $a = new ClassName; function functionName() {}
  2. Полные (ваш КО) имена. Имена, которые содержат в названии пространство имен. Например - $a = new Galaxy\ClassName;
    Причем, если текущее пространство имен - Universe, то данное имя класса будет приведено к Universe\Galaxy\ClassName. Такие имена я бы предпочитал называть относительными (мое имхо, по аналогии со ссылками и путями)
  3. Абсолютные имена. Это те имена, которые начинаются с глобального пространства имен и содержат полный путь из неймспейсов. Например - $a = new \Universe\Galaxy\ClassName;

NAMESPACE и namespace

Как и для многих сущностей в php, для пространства имен существует зарезервированная константа, именуется она как NAMESPACE и содержит она в себе имя пространства имен, в контексте которого вызывается. Если в предыдущем примере подменить строку после echo на NAMESPACE , то получится точно такой-же вывод.

namespace Universe;
function wow()
{
   echo __NAMESPACE__;
}

namespace Universe\Galaxy;
function wow()
{
   echo __NAMESPACE__;
}

wow();                  // = Universe\Galaxy
\Universe\Galaxy\wow(); // = Universe\Galaxy
\Universe\wow();        // = Universe

Соответственно, усваивая информацию о том, что пространство имен является частью имени сущностей, можно проверить, что в константах CLASS, METHOD и FUNCTION тоже теперь содержится пространство имен.
Кстати, если использовать вывод NAMESPACE находясь в глобальном пространстве имен, то будет выведена пустая строка, а не обратный слеш.

Есть еще ключевое слово namespace, которое указывает на необходимость явного указания текущего пространства имен. Хороший пример приведен в оф. документации, транслирую его сюда:

namespace MyProject;

use blah\blah as mine; // см. "Использование пространств имен: импорт/создание псевдонима имени"

blah\mine(); // вызывает функцию MyProject\blah\mine()
namespace\blah\mine(); // вызывает функцию MyProject\blah\mine()

namespace\func(); // вызывает функцию MyProject\func()
namespace\sub\func(); // вызывает функцию MyProject\sub\func()
namespace\cname::method(); // вызывает статический метод "method" класса MyProject\cname
$a = new namespace\sub\cname(); // Создает экземпляр класса MyProject\sub\cname
$b = namespace\CONSTANT; // присваивает значение константы MyProject\CONSTANT переменной $b

А также использование этого ключевого слова в глобальном пространстве имен:

namespace\func(); // вызывает функцию  func()
namespace\sub\func(); // вызывает функцию  sub\func()
namespace\cname::method(); // вызывает статический метод "method" класса cname
$a = new namespace\sub\cname(); // Создает экземпляр класса sub\cname
$b = namespace\CONSTANT; // присваивает значение константы CONSTANT переменной $b

Прочие тонкости

Если вы используете динамические имена сущностей, то стоит учесть одну небольшую особенность. В строке, содержащей имя, например, класса каждый обратный слеш должен быть экранирован, если вы хотите использовать его для пространства имен.

$className = '\\Bitrix\\Iblock\\ElementTable';
$className::query()->addFilter('IBLOCK_ID',1)->exec();

Нельзя использовать пространство имен, вложенное в пространство имен (скобочная нотация)

// Не правильно
namespace A {
	namespace B {
		function c() {};
	}
}

//Правильно
namespace A\B;
function c() {};

Об остальных аспектах читайте в официальной документации, там есть еще моменты не рассмотренные мной, но я считаю их достаточно редкими кейсами, и если вы с ними сталкиваетесь. значит вы достаточно опытны для самостоятельного их разрешения.

Про неймспейсы - все