От автора: Разрабатывая сложное веб-приложение, может возникнуть ситуация, когда при объявлении функции или переменной произойдет дублирование имен, что незамедлительно приведет к ошибке. Поэтому в данном уроке мы с Вами рассмотрим очень полезное нововведение в PHP 5.3 – пространства имен, используя которое, можно позабыть о ошибках, связанных с дублированием имен элементов Вашего скрипта.
Понятие пространства имен
Для начала рассмотрим следующие два файла. Файл file1.php
1 2 3 4 5 6 |
<?php function foo() { echo "File1"; } ?> |
Файл file2.php
1 2 3 4 5 |
<?php function foo() { echo "File2"; }?> |
При этом обратите внимание, что в каждом из них объявлена функция foo(). Сразу хотел бы отметить, что сейчас мы еще не говорим о пространствах имен и ни коем образом их не объявляем. А значит, по умолчанию используется глобальное пространство имен. Теперь обратите внимание, на еще один файл в котором мы подключим два предыдущих файла и вызовем на исполнение функцию foo(). Файл index.php
1 2 3 4 5 6 7 |
<?php include "file1.php"; include "file2.php"; foo(); ?> |
Запустив данный файл в браузере, мы, конечно же, увидим ошибку, так как в данный момент у нас объявляется две функции, с одинаковыми именами:
Так же хотел бы отметить, что обращаясь к функции foo(), в данном случае мы используем неквалификационное имя – то есть это только идентификатор конкретной функции (имя функции, без учета пространства имен). Что бы предотвратить появление ошибки – используем пространства имен. Для этого в каждом из подключаемых файлов укажем собственное пространство имен, используя ключевое слово namespace. Файл file1.php
1 2 3 4 5 6 7 |
<?php namespace File1; function foo() { echo "File1"; } ?> |
Файл file2.php
1 2 3 4 5 6 7 |
<?php namespace File2; function foo() { echo "File2"; } ?> |
Обратите внимание, что объявляя пространство имен, обязательно необходимо прописывать ключевое слово namespace перед любым кодом PHP или отображением данных на экран, в противном случае будет ошибка. Теперь, если мы обновим данные в браузере – мы получим ошибку вида:
Скорее всего Вы догадались, ошибка означает, что не найдена функция foo(). Данная функция определена, но в других пространствах имен. Файл index.php использует глобальное пространство имен, поэтому обращаясь к функции foo(), используя неквалификационное имя, мы ни как не можем получить доступ к функциям foo(), объявленным в других пространствах имен. Для того, что бы получить доступ к функции foo(), файла file1.php, мы должны в начале имени функции указать пространство имен:
1 |
File1\foo(); |
При этом в браузере мы увидим отработку вызываемой функции:
Таким образом, мы указали интерпретатору языка PHP, где искать интересующую нас функцию (в каком пространстве имен, осуществлять поиск). И в нашем случае отработала функция foo() из файла file1.php. Но, каждый раз при вызове функций, или переменных, обращаться к пространствам имен не совсем удобно, поэтому в файле index.php, мы можем объявить пространство имен, которое нас интересует и соответственно вызвать функцию foo(), используя неквалификационное имя:
1 2 3 4 5 6 7 8 |
<?php namespace File3; include "file1.php"; include "file2.php"; foo(); |
При этом, если мы перейдем браузер, то увидим, что функция нормально отрабатывает. Теперь давайте посмотрим, что будет, если я в текущем пространстве имен, обращусь к функции foo(), следующим образом:
1 |
File1\foo(); |
В этом случае мы увидим ошибку следующего вида:
Ошибка возникает, потому как мы с Вами обращаемся к функции, используя имя и пространство имен — File1\foo(), таким образом, мы используем квалификационное имя. Квалификационное имя элемента содержит пространство имен, а также идентификатор элемента (его имя). В этом случае, да и в случае с неквалификационными именами, интерпретатор PHP всегда будет добавлять объявленное пространство имен к имени вызываемого элемента. Таким образом, если мы в начале файла объявили пространство имен File1, и вызываем на исполнение функцию File1\foo() – интерпретироваться данная строка будет как File1\File1\foo(). А теперь давайте посмотрим, что будет, если я обращусь к функции foo(), следующим образом:
1 |
\File1\foo(); |
В этом случае мы увидим, что функция отлично отрабатывает.
Здесь, хотел бы отметить, что \File1\foo() – это полное квалификационное имя функции foo(). Полное квалификационное имя всегда начинается с обратного слеша и содержит полное пространство имен и идентификатор интересующего элемента (имя функции, переменой и т.д). Если мы обращаемся к полному квалификационному имени, то интерпретатор не будет учитывать объявленное ранее пространство имен при интерпретации.
Объявляя пространства имен, мы можем создавать некие иерархии пространств имен, к примеру. Файл file1.php
1 2 3 4 5 6 7 |
<?php namespace MyProject\File1; function foo() { echo "File1"; } ?> |
Файл file2.php
1 2 3 4 5 6 7 |
<?php namespace MyProject\File1; function foo() { echo "File2"; } ?> |
При этом в файле index.php, мы можем вызвать функцию foo(), следующим образом:
1 2 3 4 5 6 7 8 |
<?php namespace MyProject\File1; include "file1.php"; include "file2.php"; foo() |
Импортирование пространств имен и псевдонимы
Если в нашем проекте предусмотрена иерархия пространств имен, мы можем импортировать интересующее нас пространство имен в тот или иной файл, к примеру, в файле index.php импортируем пространство имен, используя ключевое слово use:
1 2 3 4 5 6 7 8 9 10 |
<?php use MyProject\File1; include "file1.php"; include "file2.php"; include "MyProject/File3/My2.php"; File\foo(); ?> |
При этом мы не объявляем пространство имен, а только импортируем его и для вызова функций или переменных, необходимо обращаться к их пространствам имен. Но теперь достаточно обратиться только к дочернему пространству имен и интерпретатор PHP, выполнит поиск интересующего элемента в импортируемых пространствах имен.
Импортируя пространство имен, можно указать псевдоним, используя который можно ссылаться на пространство имен, к примеру:
1 2 3 4 5 6 7 8 |
<?php use MyProject\File1 as name; include "file1.php"; include "file2.php"; name\foo(); |
В этом случае мы можем обращаться к интересующим нас элементам, используя псевдоним. При интепретации данный псевдоним будет заменен на импортируемое пространство имен, то есть, вызывая name\foo(), мы вызываем MyProject\File1\foo(). Очень удобно использовать импортирование пространств имен в связке с псевдонимами, работая с классами, к примеру, есть файл следующего содержания:
1 2 3 4 5 6 7 8 |
<?php namespace MyProject\File3; class My2 { public function foo() { echo __CLASS__.__METHOD__; } } |
Данный файл принадлежит к пространству имен MyProject\File3 и соответственно расположен по адресу MyProject\File3\My2.php, то есть иерархия пространств имен, точно соответствует структуре папок, в которых содержится данный файл. В файле index.php, мы подключим данный файл и импортируем его пространство имен, используя при этом псевдоним:
1 2 3 4 5 6 7 8 9 |
<?php use MyProject\File3\My2 as myclass; include "file1.php"; include "file2.php"; include "MyProject/File3/My2.php"; var_dump(new myclass()); |
Обратите внимание я импортирую пространство имен и псевдоним назначаю непосредственно для класса, описанного в указанном пространстве имен, таким образом при создании объекта данного класса, я могу использовать псевдоним: new myclass(). Что собственно мы и видим при обновлении страницы браузера:
Еще хотел бы обратить Ваше внимание, на следующий пример, файл index.php:
1 2 3 4 5 6 7 8 9 10 11 12 |
<?php use MyProject\File3\My2 as myclass; function __autoload($class) { echo "Имя создаваемого класса - ". $class."<br />"; $class = str_replace("\\","/",$class); include $class.'.php'; } var_dump(new myclass()); |
В данном примере, мы с Вами рассмотрим создание механизма автоматической загрузки классов, используя пространства имен. Обратите внимание, вначале импортируем пространство имен и назначаем псевдоним для имени класса. Далее описываем функцию __autoload($class), функцию автоматической загрузки классов, которая выполнится при создании ранее неопределенного объекта класса. Данная функция принимает параметром переменную $class, в которую попадет имя класса, объект которого мы пытаемся создать. В нашем случае, используется псевдоним myclass, который при интерпретации будет заменен на MyProject\File3\My2, а это полностью соответствует файловой структуре примера, остается только заменить обратные слеши на прямые и добавить расширение для файла.
При обновлении браузера, на экране мы увидим следующее:
Как Вы видите все успешно отрабатывает.
Как Вы видите пространства имен, могут быть очень полезными, особенно для больших и сложных проектов, которые разрабатываются командой разработчиков. Используя пространства имен, можно предотвратить возникновение ошибок связанных с дублированием имен различных элементов разрабатываемого скрипта, так как каждый разрабатываемый элемент, который разрабатывается отдельным человеком, будет определен в собственном пространстве имен.
На этом данный урок завершен. Всего Вам доброго и удачного кодирования!!!
Комментарии (1)