§7. Пространства имен
7.1. Определение пространства имен.
Пространства имен в PHP предназначены для группировки логически связанных классов, интерфейсов, функций и констант, позволяя при этом избегать конфликта имен (т.е. наличия одинаковых идентификаторов) при использовании сторонних фрагментов кода и библиотек или же больших фрагментов своего кода. Кроме того, пространства имен дают воможность применять псевдонимы или сокращения очень длинных имен, что с одной стороны улучшает читабельность кода, а с другой – упрощает задачу разрешения конфликта имен.
Отметим, что в PHP от пространства имен зависят только классы (включая абстрактные, интерфейсы и трейты), функции и константы, хотя при этом внутри пространства имен может находиться любой валидный php-код.
Таким образом, пространству имен в PHP можно дать следующее определение.
Пространство имен (от англ. namespace) – это некоторое абстрактное хранилище или окружение, созданное для логической группировки уникальных идентификаторов (т.е. имен), которые после определения начинают ассоциироваться с этим хранилищем или окружением.
Для объявления пространства имен используется служебное слово namespace, а все идентификаторы и код, которые нужно ассоциировать с ним, помещаются между соответствующими фигурными скобками '{...}'. При этом использование вложенных пространств имен не допускается, а файл, содержащий пространство имен, должен содержать его объявление в самом начале перед любым другим кодом, за исключением инструкции declare. Более того, наличие кода вне фигурных скобок также не допускается. Это касается, например, и того же кода HTML вне тегов '<?php' или '?>' (см. пример 7.1).
<?php //const my_const = 1; //Здесь объявлять ничего нельзя и перед тегом '<?php' тоже declare(strict_types=1);//Использовать инструкцию declare разрешается namespace myStore{ //Объявили пространство имен const my_const = 1; //Объявили константу в пространстве имен myStore class my_class{ //Объявили класс в пространстве имен myStore public $a=2; } function my_function(){ //Объявили функцию в пространстве имен myStore echo 3; } echo my_const.'<br>'; //Выведет 1 $b= new my_class; echo $b->a.'<br>'; //Выведет 2 my_function(); //Выведет 3 } //Конец области данного пространства имен //$f=5; //Здесь и после тега '?>' тоже нельзя ничего объявлять ?>
Пример 7.1. Определение пространства имен в файле PHP
Разрешается использовать синтаксис определения пространства имен и без фигурных скобок, используя после названия пространства имен точку с запятой, как показано в примере 7.2. Но мы так делать не будем, поскольку данный синтаксис не всегда применим и может приводить к ошибкам. Например, для объединения кода в глобальном пространстве имен (имеется в виду весь код, который был определен вне объявления конкретных пространств имен) с кодом в других пространствах имен, используется только синтаксис со скобками. При этом глобальный код должен быть помещен в конструкцию описания пространства имен, но без указания имени (см. пример 7.2). Также допускается комбинирование нескольких пространств имен в одном файле. Но это крайне не рекомендуется, поэтому основным применением данной возможности следует считать объединение нескольких php-файлов в один файл.
<?php //-------------------- Использование синтаксиса без скобок ---------------------- /* namespace myStore_1; //Так объявлять мы не будем const my_const = 1; //Объявили константу в пространстве имен myStore_1 echo my_const.'<br>';//Выведет 1 namespace myStore_2; //Объявили второе пространство имен const my_const = 2; //Объявили константу в пространстве имен myStore_2 echo my_const.'<br>';//Выведет 2 */ //----------------------------------------------------------------------------- namespace myStore_1{ //Объявили первое пространство имен const my_const = 1; //Объявили константу в пространстве имен myStore_1 echo my_const.'<br>';//Выведет 1 } namespace myStore_2{ //Объявили второе пространство имен const my_const = 2; //Объявили константу в пространстве имен myStore_2 echo my_const.'<br>';//Выведет 2 } namespace { //Глобальный код определяем в глобальное пространство имен $b='global code'; echo $b.'<br>'; //Выведет global code } ?>
Пример 7.2. Определение нескольких пространств имен в одном файле
7.2. Доступ к элементам пространства имен.
Так же как файлы и каталоги, пространства имен в PHP могут быть определены с использованием подуровней, например, 'my_store_1/my_store_2', создавая тем самым иерархию имен. Все это обуславливает и аналогичный принцип обращения к элементам из пространства имен, который позволяет определять требуемый элемент при помощи неполного, полного и абсолютного имени.
- Элементы с неполными именами, т.е не имеющие разделителя пространства имен '\', при обращении к ним из текущего пространства имен будут распознаваться интерпретатором с учетом добавления префикса в виде имени текущего пространства и разделителя пространства имен '\' перед именем элемента (см. пример 7.3). Если же код находится в глобальном пространстве, интерпретатор будет искать элементы с исходными именами без добавления к ним каких-либо префиксов.
- Полные имена, т.е. имена, у которых присутствует префикс в виде иерархической структуры, при обращении к ним из текущего пространства имен будут распознаваться интерпретатором с учетом текущей иерархической структуры элемента, в которую будет добавлено имя текущего пространства имен (см. пример 7.3). При нахождении кода в глобальном пространстве, интерпретатор, опять же, будет искать элементы с исходными префиксами без каких-либо изменений.
- Абсолютные имена, т.е. имена, которые начинаются с префикса глобального пространства '\', будут всегда определяться интерпретатором как есть (см. пример 7.3).
<?php namespace current_name_space{ //Объявили пространство имен const my_const = 1; //Объявили константу в текущем пространстве имен //Обратимся к константе из текущего пространства имен //PHP дополнит неполное имя до полного current_name_space\my_const echo my_const.'<br>'; //выведет 1 //PHP использует полное имя current_name_space\my_const echo \current_name_space\my_const.'<br>'; //выведет 1 //PHP преобразует в current_name_space\current_name_space\my_const //echo current_name_space\my_const.'<br>';//выведет ошибку } namespace current_name_space\myStore{ //Объявили подпространство имен const my_const = 2; //Объявили константу в current_name_space\myStore class my_class{ //Объявили класс в current_name_space\myStore function my_method(){ echo my_const.'<br>'; } } $a=new my_class; //Создали объект класса //Обратимся к константе и методу из текущего пространства имен //PHP дополнит неполное имя до полного current_name_space\myStore\my_const echo my_const.'<br>'; //выведет 2 //PHP преобразует в полное имя current_name_space\myStore\my_const echo \current_name_space\myStore\my_const.'<br>';//выведет 2 //PHP просто вызовет метод, т.к. переменные не зависят от пространства имен $a->my_method(); //выведет 2 //вызовет ошибку, т.к. к переменным пространства имен не применяются //\current_name_space\myStore\a->my_method(); } namespace{ //Выведет ошибку, т.к. в глобальном пространстве my_const не определена //echo my_const.'<br>'; //PHP обратится к current_name_space\my_const echo current_name_space\my_const.'<br>';//выведет 1 //PHP опять обратится к current_name_space\my_const echo \current_name_space\my_const.'<br>';//выведет 1 //PHP обратится к current_name_space\myStore\my_const echo current_name_space\myStore\my_const.'<br>';//выведет 2 //PHP опять обратится к current_name_space\myStore\my_const echo \current_name_space\myStore\my_const.'<br>';//выведет 2 //PHP просто вызовет метод, т.к. переменные не зависят от пространства имен //А вот если бы метод был объявлен статическим, тогда к нему можно было бы //обратиться как current_name_space\myStore\my_class::my_method() $a->my_method();//выведет 2 } ?>
Пример 7.3. Доступ к элементам пространства имен
Хотелось бы еще раз обратить внимание на то, что от пространства имен зависят только классы, интерфейсы, трейты, функции и константы. Переменные от пространства имен не зависят. Поэтому к ним нужно обращаться по обычным правилам так, как будто пространство имен вообще не было объявлено.
Если нужно обратиться к глобальным классам, функциям или константам изнутри пространства имен, следует использовать абсолютное имя (например, '\my_const'), состоящее из неполного имени элемента и префикса глобального пространства '\', который означает, что это имя должно находиться в глобальном пространстве, даже если обращение идет в контексте определенного пространства имен. Кроме того, если функция или константа не существует в пространстве имен, интерпретатор PHP попытается найти их в глобальном пространстве. Что касается классов, то они всегда преобразуются к текущему имени пространства имен. Поэтому в случае использования неполного имени и отсутствия класса в текущем пространстве имен, интерпретатор не будет делать попытки поиска в глобальном пространстве, а просто выдаст ошибку (см. пример 7.4).
<?php namespace{ //Объявляем константы в глобальном пространстве const my_const = 'global constant'; const my_const_2 = 'global constant_2'; //Объявляем функцию в глобальном пространстве function global_function(){ echo 'global function'.'<br>'; } //Объявляем класс в глобальном пространстве class global_class{ static function global_method(){ echo 'global method'.'<br>'; } } echo my_const.'<br>'; //Выведет 'global constant' //А вот здесь будет ошибка, т.к. константа еще не определена //echo current_name_space\my_const.'<br>'; global_function(); //Выведет 'global function' current_name_space\current_function(); //Выведет 'current function' global_class::global_method(); //Выведет 'global method' } namespace current_name_space{ //Объявили пространство имен //Объявляем константу в текущем пространстве имен const my_const = 'current_constant'; //PHP обратится к current_name_space\my_const echo my_const.'<br>'; //Выведет 'current_constant' //PHP использует абсолютное имя \my_const echo \my_const.'<br>'; //Выведет 'global constant' //Здесь PHP не найдет константы, поэтому перейдет к глобальному пространству echo my_const_2.'<br>'; //Выведет 'global constant_2' function current_function(){ echo 'current function'.'<br>'; } //Вызываем функцию current_name_space\current_function() current_function(); //Выведет 'current function' //Вызываем глобальную функцию \global_function() \global_function(); //Выведет 'global function' //Имена классов всегда преобразуются к текущему имени пространства имен //global_class::global_method(); //Выведет ошибку //А вот здесь все правильно, PHP воспользуется абсолютным адресом \global_class::global_method(); //Выведет 'global method' } ?>
Пример 7.4. Переход к элементам глобального пространства
Для явного запроса элемента из текущего пространства имен или подпространства может быть использовано служебное слово namespace, которое по сути представляет собой эквивалент оператора self для классов в пространстве имен (см. пример 7.5).
<?php namespace{ //Объявляем константу в глобальном пространстве const my_const = 'global constant'; //Объявляем функцию в глобальном пространстве function global_function(){ echo 'global function'.'<br>'; } //Объявляем класс в глобальном пространстве class global_class{ static function global_method(){ echo 'global method'.'<br>'; } } //PHP обратится к \my_const echo namespace\my_const.'<br>'; //Выведет 'global constant' //Вызываем функцию \current_function() namespace\global_function(); //Выведет 'global function' namespace\global_class::global_method(); //Выведет 'global method' } namespace current_name_space{ //Объявили пространство имен //Объявляем константу в текущем пространстве имен const my_const = 'current_constant'; //Объявляем функцию в текущем пространстве имен function current_function(){ echo 'current function'.'<br>'; } //Объявляем класс в текущем пространстве имен class current_class{ static function current_method(){ echo 'current method'.'<br>'; } } //PHP обратится к current_name_space\my_const echo namespace\my_const.'<br>'; //Выведет 'current_constant' //Вызываем функцию current_name_space\current_function() namespace\current_function(); //Выведет 'current function' //Вызываем метод current_name_space\current_method() namespace\current_class::current_method(); //Выведет 'current method' } ?>
Пример 7.5. Еще одно предназначение служебного слова namespace
7.3. Импорт имени в пространство имен и создание псевдонима имени.
В PHP имеется возможность импорта имен из других пространств в текущее пространство имен. Делается это при помощи уже знакомого нам служебного слова use, которое должно быть указано внутри объявления пространства имен и не может быть заключено в блок (например, нельзя использовать его внутри тела функции). Это вызвано тем, что импорт выполняется во время компиляции, а не во время исполнения. Кроме того, одновременно с импортированием имеется возможность использования псевдонимов, которые создаются при помощи служебного слова as и позволяют сократить запись длинных имен (см. пример 7.6).
<?php namespace name_space_1{ //Объявили пространство имен //Объявляем константу в текущем пространстве имен const current_const_1 = 'current_constant_1'; //Объявляем функцию в текущем пространстве имен function current_function_1(){ echo 'current_function_1'.'<br>'; } //Объявляем класс в текущем пространстве имен class current_class_1{ static function current_method_1(){ echo 'current_method_1'.'<br>'; } } } namespace name_space_2{ //Объявили пространство имен //Импортируем имя константы из name_space_1 и создаем ей псевдоним use const name_space_1\current_const_1 as B; //Импортируем имя функции из name_space_1 и создаем ей псевдоним use function name_space_1\current_function_1 as f; //Импортируем имя класса из name_space_1 и создаем ей псевдоним //При этом писать слово class не нужно use name_space_1\current_class_1 as CL; //Импортируем имя функции из глобального пространства и создаем ей псевдоним use function \global_function as gl_f; echo B.'<br>'; //Выведет 'current_constant_1' f(); //Выведет 'current_function_1' $a=new CL; //Создаем объект класса name_space_1\current_class_1 $a->current_method_1();//Выведет 'current_method_1' gl_f(); //Выведет 'global_function' //Объявляем константу в текущем пространстве имен const current_const_2 = 'current_constant_2'; //Объявляем функцию в текущем пространстве имен function current_function_2(){ echo 'current_function_2'.'<br>'; } //Объявляем класс в текущем пространстве имен class current_class_2{ static function current_method_2(){ echo 'current_method_2'.'<br>'; } } } namespace{ //Создаем псевдоним пространства имен для сокращения записи use name_space_2 as ns_2; //Объявляем функцию в глобальном пространстве function global_function(){ echo 'global_function'.'<br>'; } echo ns_2\current_const_2.'<br>'; //Выведет 'current_constant_2' ns_2\current_function_2(); //Выведет 'current_function_2' $b=new ns_2\current_class_2; //Объект класса name_space_2\current_class_2 $b->current_method_2(); //Выведет 'current_method_2' } ?>
Пример 7.6. Импорт и создание псевдонимов имен
Следует помнить, что импорт распространяется только на неполные и полные имена. Кроме того, в случае импортирования имени класса служебное слово class перед его именем писать не нужно, а вот при импортировании имен функций и констант нужно писать, соответственно, function и const.
Также отметим, что создание псевдонимов применимо и к именам пространств имен, что позволяет сократить запись, например, в случае длинного иерархического имени (см. пример 7.6).
Контрольные вопросы и задания
- Дайте определение пространству имен.
- Опишите синтаксис объявления пространства имен.
Разрешается ли создавать
вложенные пространства имен? - Как объединить код в глобальном пространстве с кодом объявленного пространства имен?
- Можно ли создать несколько пространств имен в одном файле?
- Опишите механизм обращения интерпретатора к элементам
текущего пространства
имен с неполными, полными и абсолютными именами. - В каких случаях интерпретатор будет обращаться к глобальным
классам, функциям или
константам из текущего пространства имен? - Как еще может быть использовано служебное слово namespace?
- Опишите синтаксис импортирования имен в текущее пространство имен и создания их псевдонимов.
Словарь новых английских слов
namespace [neɪmˈspeɪs] – пространство имен. declare [dɪˈklɛː] – объявлять, провозглашать. |
storage [ˈstɔːrədʒ] – хранилище, склад, память. current [ˈkʌr(ə)nt] – текущий. |