是否可以获取已定义的命名空间列表

Don*_*eba 31 php namespaces

嗨,您好,

我想知道是否有一种方法在php 5.3+中获取应用程序中定义的命名空间列表.所以

如果 file 1 has namespace FOOfile 2 has namespace BAR

现在,如果我在文件3中包含文件1和文件2,就像知道某种函数调用那样加载了命名空间FOO和BAR.

我想实现这一点,以确保在检查类是否存在(使用is_callable)之前,我的应用程序中的模块已加载.

如果这是不可能的,我想知道是否有一个函数来检查是否定义了特定的命名空间,如is_namespace().

希望你明白这个主意.而我正在努力实现的目标

Ham*_*ish 40

首先,看看是否存在一个类,使用过class_exists.

其次,你可以得到的类的列表与命名空间的使用get_declared_classes.

在最简单的情况下,您可以使用它来从所有声明的类名中查找匹配的命名空间:

function namespaceExists($namespace) {
    $namespace .= "\\";
    foreach(get_declared_classes() as $name)
        if(strpos($name, $namespace) === 0) return true;
    return false;
}
Run Code Online (Sandbox Code Playgroud)

另一个例子,以下脚本生成声明的命名空间的分层数组结构:

<?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);
Run Code Online (Sandbox Code Playgroud)

得到:

Array
(
    [FirstNamespace] => 
    [SecondNamespace] => Array
        (
            [FirstSubNamespace] => 
        )
    [ThirdNamespace] => Array
        (
            [FirstSubNamespace] => 
            [SecondSubNamespace] => 

        )
)
Run Code Online (Sandbox Code Playgroud)


Kev*_*eno 14

我知道这个问题已经有了答案,但我想为我认为你的问题提供一个更现实的解决方案.如果我昨天有更多时间发表评论,我会发布这个.对不起,我没有.

听起来OP有一个模块系统,他需要知道在允许调用之前是否加载了特定模块.

首先,我想说使用命名空间只是简单地声明模块是IMO,滥用它们的用途.如果您遵循namespacing到字母的目的,您的结构可能看起来更像这样:

您的整个系统应该位于自己的命名空间中.我们称之为命名空间System.然后,模块可能会在System\Module命名空间下.然后,根据复杂性,每个模块可能都有一个命名空间System\Module.以你的例子,System\Module\FOOSystem\Module\BAR.

现在,让我们开始制作一个在加载时注册自己的模块系统.

首先,我们需要一个注册的地方.让我们称之为System\Module\Registry,因为可能会有很多不同的注册表,它将实现System\iRegistry.为简洁起见,我只是张贴System\Module\Registry.很有可能,它也会实现某种全局一致性模型,比如单身人士,但我也没有表现出来.这里是:

<?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.");
        }
    }
}
?>
Run Code Online (Sandbox Code Playgroud)

现在,在每个模块中,您需要在加载文件时调用此寄存器函数.有几种方法可以做到这一点.第一个是在模块的命名空间中有一些代码,它们在加载时运行,类似于典型的逐行代码:

namespace System\Module\FOO
{
    // Load this module
    $system->module->register("FOO");
}
Run Code Online (Sandbox Code Playgroud)

以上将意味着代码重复.您也可以使用自动加载,这样"注册"代码就在一个地方.这是一个非常基本的概念:

spl_autoload_register(
    function ($className)
    {
        // Code to load files.
        // Once loaded register our modules.
        if( $namespace = "System\\Module" )
        {
            $system->module->register( $classname );
        }
    }
); 
Run Code Online (Sandbox Code Playgroud)

另一种可行的方法是为具有特定功能的模块定义接口,以便在初始化模块时进行注册.但是,这意味着需要首先加载模块,并且可能会根据您的需要导致模块自身出现问题.

这样做之后:

  • 您拥有一致的命名空间,可供模块使用
  • 你有一个一致的界面,允许任何模块知道如何自己注册
  • 您可以在将来轻松扩展模块或注册表接口以获取新内容,同时保持代码清晰易懂.
  • 而且,最重要的是,您将知道您的模块实际上会声明它们已加载和/或准备好,而不是依靠黑魔法为您完成.