Только для читателей Lifeexample возможно открыть интернет-магазин на Moguta.CMS со скидкой в 15%
Пространство имен PHP (Внедрение в проект)
Здравствуйте, уважаемые читатели блога LifeExample, сегодня мы поговорим о том, как внедрить пространства имен в PHP проект. Вы наверняка сталкивались с ситуацией: подключаете стороннюю библиотеку в проект, а в ней встречаются названия классов, которые вы уже где-то в своем коде используете (например, распространенные названия такие как ‘Logger’ или ‘Model’).
Не всегда получается поправить эти конфликты с пересекающимися именами из-за совместимости резервных файлов или внешних классовых ссылок в базе данных.
Ситуация может быть еще хуже, если вы не можете изменить стороннюю библиотеку, потому что последняя является, например, закрытым источником (по какой либо причине). В таком случае, у вас не получится использовать подобную библиотеку и приходится от нее отказываться.
Сегодня мы познакомимся с механизмом позволяющим легко внедрить пространства имен в PHP проект используя, которые можно быть спокойным за совместимость проекта со сторонними библиотеками.
Что такое пространство имен PHP
Пространство имён (англ. namespace) — некоторое окружение, созданное для группировки уникальных идентификаторов (то есть имён).
Проще говоря если вы инкапсулируете код PHP в пространство имен, вы можете пользоваться любой другой библиотекой, у которой другое пространство имен. При этом имена классов и переменных могут быть идентичными в разных пространствах, и это не приведет к конфликту.
Внедрение в проект
При внедрении пространств имен в имеющийся проект, нужно набраться терпения т.к. сделать это придется для всех классов в проекте, а с первого раза вряд ли получится т.к. процесс долгий, но он того стоит. Упростить процесс получится, если вы используете автозагрузку класса.
Основная процедура состоит в создании класса псевдонимов при пустом запрашиваемом классе и наличии необходимых названий в найденном классе.
Рассмотрим на примере:
1 2 3 | //файл: myclass.php namespace Scavix\SomeCoolProject; class MyClass { /* тело класса */ } |
Приведенный файл описывает класс MyClass в пространстве имен Scavix\SomeCoolProject.
Стандартный механизм автозагрузки для названий классов выглядит примерно так:
1 2 3 4 5 6 7 8 | // Файл: autoloader.php function system_spl_autoload($class_name) { // используем некоторую функцию для поиска файла с объявляемым классом $file = __search_file_for_class($class_name); require_once($file); } spl_autoload_register("system_spl_autoload",true,true); |
Стандартные PHP функции: __search_file_for_class, spl_autoload_register.
В файле index.php подключим автозагрузчик и попробуем инициализировать экземпляр класса MyClass из файла myclass.php, двумя способами.
1 2 3 4 | // file: index.php require_once("autoloader.php"); $mc = new MyClass(); // Выбросит ошибку ‘Class not found’ $mc = new Scavix\SomeCoolProject\MyClass(); // Успешно создаст экземпляр класса |
Конечно ошибка ‘Class not found’ здесь умышленная и сделана для примера. Чтобы код работал придется оставить только строку
1 | $mc = new Scavix\SomeCoolProject\MyClass(); |
При наличии такого автозагрузчика придется всем классам проекта задавать пространства имен и вызывать их аналогичным образом.
Согласитесь, если проект объемный, то сразу сделать это без проблем будет крайне не просто. Хотелось бы, чтобы при внедрении пространств имен в проект можно было подключать классы, как обычным методом, так и используя пространство имен.
Давайте расширим автозагрузчик для упрощения внедрения пространства имен PHP. Будем создавать псевдоним класса для предотвращения ошибки ‘Class not found’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | // file: autoloader_ex.php function system_spl_autoload($class_name) { if( strpos($class_name, "\\") !== false ) { $orig = $class_name; $class_name = array_pop(explode("\\",$class_name)); } // используем некоторую функцию для поиска файла с объявляемым классом $file = __search_file_for_class($class_name); // запомним объявленные классы, и подключим файлы $pre = get_declared_classes(); require_once($file); $post = array_unique(array_diff(get_declared_classes(), $pre)); // Создадим псевдонимы для новых классов foreach( $post as $cd ) { $d = explode("\\",$cd); if( count($d) > 1 ) { create_class_alias($cd,array_pop($d)); } } //Получим определяемые классы. Предполагается что в одном файле один класс или интерфейс $def = array_pop($post); if( !isset($orig) && !$def ) { foreach( array_reverse($pre) as $c ) { if( !ends_with($c,$class_name) ) continue; create_class_alias($c,$class_name,true); break; } } else { $class_name = isset($orig)?$orig:$class_name; if( strtolower($def) != strtolower($class_name) && ends_iwith($def,$class_name) ) { create_class_alias($def,$class_name,true); } } } spl_autoload_register("system_spl_autoload",true,true); function create_class_alias($original,$alias,$strong=false) { if( $strong ) class_alias($original,$alias); // Сохраняет алиас в глобальные переменны $alias = strtolower($alias); if( isset($GLOBALS['system_class_alias'][$alias]) ) { if( $GLOBALS['system_class_alias'][$alias] == $original ) return; if( !is_array($GLOBALS['system_class_alias'][$alias]) ) $GLOBALS['system_class_alias'][$alias] = array($GLOBALS['system_class_alias'][$alias]); $GLOBALS['system_class_alias'][$alias][] = $original; } else $GLOBALS['system_class_alias'][$alias] = $original; } |
Стандартные PHP функции: __search_file_for_class, spl_autoload_register, get_declared_classes, ends_with, ends_iwith, class_alias.
Немого изменим файл index.php:
1 2 3 4 | // file: index.php require_once("autoloader_ex.php"); $mc = new MyClass(); // OK $mc = new Scavix\SomeCoolProject\MyClass(); // OK |
Теперь, благодаря расширенной функции автозагрузчика классов можно постепенно переносить свой проект для использования пространств имен в PHP, без страха положить проект.
Когда применять пространства имен в PHP
Как вы могли заметить, пространство имен – это полезная штука! Но нужно применять его правильно и использовать только там где необходимо. Поэтому следуйте следующим правилам:
- Используйте уникальный корень для пространства имен ;
- Используйте только одно пространство имен в каждом файле;
- Проверьте наличие в пространстве имен каждого класса/интерфейса;
- Поставьте каждый класс/интерфейс в собственный файл и ничего больше туда не добавляйте;
- Не добавляйте функции в пространство имен.
Спасибо за внимание, надеюсь данный материал будет вам полезен если вы захотите внедрить в ваш проект пространство имен PHP.
Читайте также похожие статьи:
Чтобы не пропустить публикацию следующей статьи подписывайтесь на рассылку по E-mail или RSS ленту блога.
Комментарии
Неужели трудно было снадбить урок простейшими примерами?
А то для людей типа меня с конкретным типом мышления, этот урок не принес пользы, но вызвал чувство досады на свою бестолковость.
Статья рассчитана на людей имеющих представление о работе пространствами имен. Ключевой смысл статьи не в том чтобы объяснить механизм работы с пространством имен в PHP, а в том как внедрять их в проект. Возможно в будущем я напишу статью именно о том, что такое пространство имен в PHP и как этим пользоваться.
зачем писать: «Стандартные PHP функции: __search_file_for_class»?
Я не нашел такой функции.Я так понял,что там должна быть какай то пользовательская функция,которая находит файл с нужным классом.