是否可以获得已定义名称空间的列表

Posted

技术标签:

【中文标题】是否可以获得已定义名称空间的列表【英文标题】:is it possible to get list of defined namespaces 【发布时间】:2011-07-10 16:54:20 【问题描述】:

你好,

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

如果 file 1 has namespace FOOfile 2 has namespace BAR

现在,如果我在文件 3 中包含文件 1 和文件 2,我想通过某种函数调用来知道命名空间 FOO 和 BAR 是否已加载。

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

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

希望您能理解。以及我想要实现的目标

【问题讨论】:

简而言之,答案是否定的。没有 php 方法可以做到这一点。坚持使用 class_exists 或 is_callable。 @Kevin Peno,不想这么说,但正如您在下面看到的,有一种方法可以获取已加载的命名空间。 对不起,我是直接用 PHP 说的。如,一个检查命名空间是否已声明/正在使用的函数。对不起,如果我不够清楚。 @Kevin Peno,没问题,但我相信编程比语言提供的功能更多。像下面的函数一样开箱即用就是一个很好的例子。 :) 你在is_callable 上虽然:) 【参考方案1】:

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

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

首先,我想说的是,IMO 仅仅使用命名空间来声明模块处于活动状态是滥用它们的用途。如果您按照字母命名空间的目的,您的结构可能看起来更像这样:

您的整个系统应该在自己的命名空间中。让我们将该命名空间称为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.");
        
    

?>

现在,在每个模块中,您需要在文件加载时调用此注册函数。有几种方法可以做到这一点。首先是在模块的命名空间中有一些代码在加载时运行,类似于典型的过程代码:

namespace System\Module\FOO

    // 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 );
        
    
); 

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

这样做之后:

您有一个一致的命名空间供模块使用 你有一个一致的接口,它允许任何模块知道如何注册自己 您可以在未来轻松扩展模块或注册表接口以适应新事物,同时保持代码简洁易懂。 而且,最重要的是,您将知道您的模块实际上会声明它们已加载和/或准备就绪,而不是依靠黑魔法为您完成。

【讨论】:

感谢您的这篇好文章 :) 这实际上是一种比上述解决方案更温和的解决方案。我很感激即使在给出并接受了答案之后,您仍然为如何实现 m 目标提供了一个不可告人的例子。再次感谢【参考方案2】:

首先,查看一个类是否存在,使用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] => 

        )
)

【讨论】:

我不知道附加到实际类名的命名空间。感谢您的回答和示例,非常有帮助,正是我所需要的。 感谢大量处理只是为了获得命名空间名称。有趣的概念。 不得不感谢这个答案。我将它昵称为命名空间的“var_dump”。 :) 这个答案只是部分正确。如果命名空间存在但声明它的文件没有声明任何类,则它不起作用...

以上是关于是否可以获得已定义名称空间的列表的主要内容,如果未能解决你的问题,请参考以下文章

名称空间

python中怎样查看已加载的命名空间中所有变量和函数

day18 函数定义参数;名称空间;全局变量及局部变量。

名称空间“System.Runtime”中不存在类型或命名空间名称“缓存”

python_day04 函数嵌套 名称空间和作用域 闭包 装饰器 迭代器 生成器 列表解析 三元表达式 生成器表达式

截获Flask restplus名称空间类的验证错误