#php #namespaces
#php #пространства имен
Вопрос:
ПРИВЕТ,
Мне было интересно, есть ли в php 5.3 способ получить список определенных пространств имен в приложении. итак
если file 1 has namespace FOO
и file 2 has namespace BAR
Теперь, если я включу файл 1 и файл 2 в файл 3, я хотел бы узнать с помощью какого-то вызова функции, что загружаются пространства имен FOO и BAR.
Я хочу добиться этого, чтобы убедиться, что модуль в моем приложении загружен, прежде чем проверять, существует ли класс (с is_callable ).
Если это невозможно, я хотел бы знать, есть ли функция для проверки определения определенного пространства имен, что-то вроде is_namespace() .
Надеюсь, вы поняли идею. и чего я пытаюсь достичь
Комментарии:
1. Короче говоря, ответ отрицательный. На php нет способа сделать это. Придерживайтесь class_exists или is_callable .
2. @Kevin Peno, ненавижу это говорить, но, как вы можете видеть ниже, есть способ получить загруженное пространство имен.
3. Извините, но я говорил непосредственно в PHP. Например, функция для проверки, объявлено ли / используется ли пространство имен. Извините, если я был недостаточно ясен.
4. @Kevin Peno, без проблем, но я считаю, что в программировании есть нечто большее, чем функции, предоставляемые языком. Хорошим примером этого является нестандартное мышление, подобное приведенной ниже функции. 🙂 вы правы
is_callable
, хотя 🙂
Ответ №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;
}
Другой пример, следующий скрипт создает иерархическую структуру массива объявленных пространств имен:
<?php
namespace FirstNamespace;
class Bar {}
namespace SecondNamespace;
class Bar {}
namespace ThirdNamespaceFirstSubNamespace;
class Bar {}
namespace ThirdNamespaceSecondSubNamespace;
class Bar {}
namespace SecondNamespaceFirstSubNamespace;
class Bar {}
$namespaces=array();
foreach(get_declared_classes() as $name) {
if(preg_match_all("@[^\] (?=\)@iU", $name, $matches)) {
$matches = $matches[0];
$parent =amp;$namespaces;
while(count($matches)) {
$match = array_shift($matches);
if(!isset($parent[$match]) amp;amp; count($matches))
$parent[$match] = array();
$parent =amp;$parent[$match];
}
}
}
print_r($namespaces);
Дает:
Array
(
[FirstNamespace] =>
[SecondNamespace] => Array
(
[FirstSubNamespace] =>
)
[ThirdNamespace] => Array
(
[FirstSubNamespace] =>
[SecondSubNamespace] =>
)
)
Комментарии:
1. Я не знал пространств имен, где они привязаны к фактическому имени класса. Спасибо за ответ и пример, очень полезный и именно то, что мне было нужно.
2. Большое спасибо за обработку, чтобы получить имя пространства имен. Интересная концепция.
3. Должен сказать спасибо за этот ответ. Я называю его «var_dump» пространств имен. 🙂
4. Этот ответ верен лишь частично. Это не работает, если пространство имен существует, но файл, в котором оно объявлено, не объявляет никаких классов…
Ответ №2:
Я знаю, что на этот вопрос уже есть ответ, но я хотел предоставить более реалистичное решение того, в чем, по моему мнению, заключается ваша проблема. Если бы у меня было больше времени вчера, когда я делал свой комментарий, я бы опубликовал это. Извините, что я этого не сделал.
Похоже, у OP есть модульная система, которую ему нужно знать, загружен ли конкретный модуль, прежде чем разрешить его вызов.
Во-первых, я хотел бы сказать, что использование пространств имен просто для объявления активных модулей — это, IMO, злоупотребление тем, для чего они предназначены. Если вы будете следовать цели пространства имен до буквы, ваша структура может выглядеть примерно так:
Вся ваша система должна находиться в своем собственном пространстве имен. Давайте назовем это пространство System
имен . Тогда модули, скорее всего, будут находиться в SystemModule
пространстве имен. Тогда, в зависимости от сложности, было бы возможно, что каждый модуль может иметь пространство имен под SystemModule
. Принимая ваши примеры, SystemModuleFOO
и SystemModuleBAR
.
Теперь давайте приступим к созданию модульной системы, которая регистрирует себя при загрузке.
Во-первых, нам нужно место для регистрации. Давайте назовем это SystemModuleRegistry
, и, поскольку, вероятно, будет много разных реестров, он будет реализовывать SystemiRegistry
. Для краткости я только публикую SystemModuleRegistry
. По всей вероятности, он также будет реализовывать какую-то глобальную модель согласованности, например, одноэлементную, но я этого тоже не показываю. Вот оно:
<?php
namespace SystemModule
{
class Registry extends SystemRegistry
{
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.");
}
}
}
?>
Теперь в каждом модуле вам нужно будет вызвать эту функцию register при загрузке файла. Есть несколько способов сделать это. Во-первых, в пространстве имен вашего модуля должен быть некоторый код, который выполняется при загрузке, аналогичный типичному исходному коду:
namespace SystemModuleFOO
{
// Load this module
$system->module->register("FOO");
}
Однако это означало бы дублирование кода. Вместо этого вы также можете использовать автозагрузку, чтобы весь код «регистрации» был в одном месте. Вот очень простая концепция этого:
spl_autoload_register(
function ($className)
{
// Code to load files.
// Once loaded register our modules.
if( $namespace = "System\Module" )
{
$system->module->register( $classname );
}
}
);
Другим возможным способом сделать это было бы определить интерфейс для модулей с определенной функцией для регистрации при инициализации модуля. Это, однако, означает, что модуль должен быть загружен первым и может вызвать его собственные проблемы в зависимости от ваших потребностей.
После этого:
- у вас есть согласованное пространство имен для модулей для жизни
- у вас есть согласованный интерфейс, который позволяет любому модулю знать, как зарегистрироваться
- вы можете легко расширить интерфейсы модуля или реестра в будущем для новых вещей, сохраняя при этом свой код чистым и понятным.
- и, самое главное, вы будете знать, что ваши модули фактически объявят, что они загружены и / или готовы, вместо того, чтобы полагаться на черную магию, чтобы сделать это за вас.
Комментарии:
1. спасибо за этот приятный пост 🙂 На самом деле это более языческое решение, чем приведенное выше. Я ценю, что даже после того, как ответ был дан и принят, вы предоставили скрытый пример того, как достичь m цели. еще раз спасибо