Всем привет,
Мне было интересно, есть ли способ в php 5.3+ получить список определенных пространств имен в приложении. так
если file 1 has namespace FOO
а file 2 has namespace BAR
Теперь, если я включаю файл 1 и файл 2 в id файла 3, чтобы узнать, с каким-то вызовом функции, загружаются пространство имен FOO и BAR.
Я хочу достичь этого, чтобы убедиться, что модуль в моем приложении загружен, прежде чем проверять, существует ли класс (с is_callable).
Если это невозможно, я хотел бы знать, есть ли функция для проверки того, определено ли определенное пространство имен, например is_namespace ().
Надеюсь, вы получите эту идею. и чего я пытаюсь достичь
Во-первых, чтобы увидеть, существует ли класс, используется class_exists
.
Во-вторых, вы можете получить список классов с пространством имен, используя get_declared_classes
.
В простейшем случае вы можете использовать это, чтобы найти подходящее пространство имен из всех объявленных имен классов:
function namespaceExists($namespace) { $namespace .= "\\"; foreach(get_declared_classes() as $name) if(strpos($name, $namespace) === 0) return true; return false; }
Другой пример: следующий скрипт создает иерархическую структуру массива объявленных пространств имен:
<?php namespace FirstNamespace; class Bar {} namespace SecondNamespace; class Bar {} namespace ThirdNamespace\FirstSubNamespace; class Bar {} namespace ThirdNamespace\SecondSubNamespace; class Bar {} namespace SecondNamespace\FirstSubNamespace; class Bar {} $namespaces=array(); foreach(get_declared_classes() as $name) { if(preg_match_all("@[^\\\]+(?=\\\)@iU", $name, $matches)) { $matches = $matches[0]; $parent =&$namespaces; while(count($matches)) { $match = array_shift($matches); if(!isset($parent[$match]) && count($matches)) $parent[$match] = array(); $parent =&$parent[$match]; } } } print_r($namespaces);
дает:
Array ( [FirstNamespace] => [SecondNamespace] => Array ( [FirstSubNamespace] => ) [ThirdNamespace] => Array ( [FirstSubNamespace] => [SecondSubNamespace] => ) )
Я знаю, что у этого вопроса уже есть ответ, но я хотел бы предложить более реалистичное решение того, что я считаю своей проблемой. Если бы у меня было больше времени вчера, когда я сделал свой комментарий, я бы разместил это. Извините, что я этого не сделал.
Похоже, что OP имеет модульную систему, которую он должен знать, если какой-либо конкретный модуль загружен до разрешения вызова.
Во-первых, я хотел бы сказать, что использование пространств имен просто для объявления активных модулей – это ИМО, злоупотребляя тем, для чего они предназначены. Если вы будете следовать назначению имен на письмо, ваша структура может выглядеть примерно так:
Вся ваша система должна находиться в своем собственном пространстве имен. Назовем эту System
пространств имен. Тогда модули, вероятно, будут находиться в пространстве имен System\Module
. Затем, в зависимости от сложности, возможно, что каждый модуль может иметь пространство имен в System\Module
. Пользуясь примерами, System\Module\FOO
и System\Module\BAR
.
Теперь давайте займемся созданием модульной системы, которая регистрируется при загрузке.
Во-первых, нам нужно место для регистрации. Давайте назовем System\Module\Registry
и, поскольку, вероятно, будет много разных реестров, оно будет внедрять System\iRegistry
. Для краткости я публикую System\Module\Registry
. По всей вероятности, он также реализует какую-то глобальную модель согласованности, такую как singleton, но я тоже не показываю. Вот:
<?php namespace System\Module { class Registry extends System\Registry { protected $registered = array(); public function register( $name=null ) { $this->registered[] = $name; } public function isRegistered( $module ) { // Code to find module } public function getModule( $module ) { // Code to find module // OR, if you can't find it... throw new ModuleNotRegisteredException("Module named \"{$module}\" could not be found in the registry."); } } } ?>
Теперь в каждом модуле вам нужно будет вызвать эту функцию регистрации, когда файл будет загружен. Есть несколько способов сделать это. Первый заключается в том, чтобы иметь некоторый код в пространстве имен вашего модуля, который работает при нагрузке, похожей на типичный процедурный код:
namespace System\Module\FOO { // Load this module $system->module->register("FOO"); }
Вышеупомянутое будет означать дублирование кода. Вы можете также использовать autoload для этого, таким образом, «регистрирующий» код находится в одном месте. Вот очень простая концепция:
spl_autoload_register( function ($className) { // Code to load files. // Once loaded register our modules. if( $namespace = "System\\Module" ) { $system->module->register( $classname ); } } );
Другим возможным способом сделать это будет определение интерфейса для модулей с определенной функцией для регистрации, когда модуль инициализируется. Это, однако, означает, что модуль должен быть загружен первым и может вызвать собственные проблемы в зависимости от ваших потребностей.
После этого: