§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;                 //Здесь и после тега '?&gt;' тоже нельзя ничего объявлять 
?>

Пример 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', создавая тем самым иерархию имен. Все это обуславливает и аналогичный принцип обращения к элементам из пространства имен, который позволяет определять требуемый элемент при помощи неполного, полного и абсолютного имени.

<?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).

Контрольные вопросы и задания

  1. Дайте определение пространству имен.
  2. Опишите синтаксис объявления пространства имен. Разрешается ли создавать
    вложенные пространства имен?
  3. Как объединить код в глобальном пространстве с кодом объявленного пространства имен?
  4. Можно ли создать несколько пространств имен в одном файле?
  5. Опишите механизм обращения интерпретатора к элементам текущего пространства
    имен с неполными, полными и абсолютными именами.
  6. В каких случаях интерпретатор будет обращаться к глобальным классам, функциям или
    константам из текущего пространства имен?
  7. Как еще может быть использовано служебное слово namespace?
  8. Опишите синтаксис импортирования имен в текущее пространство имен и создания их псевдонимов.

Словарь новых английских слов

namespace [neɪmˈspeɪs] – пространство имен.
declare [dɪˈklɛː] – объявлять, провозглашать.
storage [ˈstɔːrədʒ] – хранилище, склад, память.
current [ˈkʌr(ə)nt] – текущий.

 

belarusweb.net   ©  Петр Романовский, Минск, 2016.