возможно ли получить список определенных пространств имен

#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 цели. еще раз спасибо