Возможно ли получить список определенных пространств имен
HI,
Мне было интересно, есть ли способ в php 5.3+ получить список определенных пространств имен в приложении.
поэтому
если file 1 has namespace FOO
а также file 2 has namespace BAR
Теперь, если я включаю файл 1 и файл 2 в файл 3 id, как знать с каким-то вызовом функции, загружаются пространство имен FOO и BAR.
Я хочу достичь этого, чтобы убедиться, что модуль в моем приложении загружен, прежде чем проверять, существует ли класс (с is_callable).
Если это невозможно, я хотел бы знать, есть ли функция для проверки того, определено ли определенное пространство имен, например is_namespace().
Надеюсь, вы получите эту идею. и что я пытаюсь достичь
Ответы
Ответ 1
Во-первых, чтобы увидеть, существует ли класс, используется class_exists
.
Во-вторых, вы можете получить список классов с пространством имен, используя get_declared_classes
.
В простейшем случае вы можете использовать это, чтобы найти подходящее пространство имен из всех объявленных имен классов:
function namespaceExists($namespace) {
$namespace .= "\\";
foreach(get_declared_classes() as $name)
if(strpos($name, $namespace) === 0) return true;
return false;
}
Другой пример: script создает иерархическую структуру массива объявленных пространств имен:
<?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] =>
)
)
Ответ 2
Я знаю, что у этого вопроса уже есть ответ, но я хотел бы предложить более реалистичное решение того, во что я верю, ваша проблема. Если бы у меня было больше времени вчера, когда я сделал свой комментарий, я бы разместил это. Извините, что я этого не сделал.
Похоже, что 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 );
}
}
);
Другим возможным способом сделать это будет определение интерфейса для модулей с определенной функцией для регистрации при инициализации модуля. Это, однако, означает, что модуль должен быть загружен первым и может вызвать его собственные проблемы в зависимости от ваших потребностей.
После этого:
- У вас есть постоянное пространство имен для модулей, которые будут жить в
- У вас есть согласованный интерфейс, который позволяет любому модулю знать, как зарегистрировать себя
- вы можете легко расширить интерфейс модуля или реестра в будущем для новых вещей, сохраняя при этом свой код понятным и понятным.
- и наиболее важно, вы узнаете, что ваши модули фактически заявят, что они загружены и/или готовы вместо того, чтобы полагаться на черную магию, чтобы сделать это для вас.