2011-03-07 86 views
27

您好,是否有可能获得已定义的命名空间的列表

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

如果 file 1 has namespace FOOfile 2 has namespace BAR

现在,如果我包括档案文件1和文件2 3我想知道有某种函数调用的命名空间FOO和BAR被加载。

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

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

希望你明白了。我试图实现什么

+0

总之,答案是否定的。有没有这样做的PHP方式。坚持class_exists或is_callable。 – 2011-03-07 23:46:19

+0

@Kevin Peno,讨厌这么说,但正如你在下面看到的,有一种方法可以获得加载的名称空间。 – DonSeba 2011-03-08 07:44:00

+0

对不起,但我直接用PHP说话。和in一样,一个函数检查一个名字空间是否被声明/正在使用。对不起,如果我不够清楚。 – 2011-03-08 17:15:01

回答

34

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

     ) 
) 
+0

我不知道附加到实际类名的命名空间。感谢答案和例子,非常有帮助,正是我需要的。 – DonSeba 2011-03-08 06:33:30

+0

感谢大量的处理,以获得一个名称空间的名称。虽然有趣的概念。 – 2011-03-08 17:21:36

+0

不得不说谢谢你的回答。我将它命名为命名空间的“var_dump”。 :) – adamst85 2015-06-08 06:22:34

13

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

这听起来像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."); 
     } 
    } 
} 
?> 

现在,在每个模块中,您需要在文件加载时调用该寄存器函数。有几种方法可以做到这一点。首先是在你的模块的名字空间一些代码,类似典型proceedural代码加载运行:

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

这样做将是定义模块的接口与特定功能时,模块初始化注册的另一种可能的方式。但是,这意味着模块需要首先加载,并且可能会根据您的需求导致它自己的问题。

这样做后:

  • 你有一个一致的命名空间模块住在
  • 你有一个一致的接口,它允许任何模块知道如何注册自己
  • 您可以轻松地扩展模块或注册表接口,用于新事物,同时保持代码清洁且易于理解。
  • 最重要的是,你会知道你的模块会实际声明他们已经加载和/或准备好,而不是依靠黑魔法来为你做。
+1

谢谢你这个不错的帖子:)这实际上是一个比上面更多的gentile解决方案。我很感激,即使答案已经被接受并被接受,你为如何实现目标提供了另一个例子。再次感谢 – DonSeba 2011-03-09 11:38:43

+0

@BFDatabaseAdmin感谢您的编辑! :) – 2015-04-02 19:52:05

相关问题