你好,
我想知道在php 5.3+中是否有办法获取应用程序中定义的命名空间列表。 所以
如果
file 1 has namespace FOO
和
file 2 has namespace BAR
现在如果我在文件3中包含文件1和文件2,就像知道某种函数调用那样加载了命名空间FOO和BAR。
我想实现这一目的,以确保在检查类是否存在(使用is_callable)之前加载了我的应用程序中的模块。
如果这是不可能的,我想知道是否有一个函数来检查是否定义了特定的命名空间,如is_namespace()。
希望你能得到这个想法。以及我想要实现的目标
答案 0 :(得分:37)
首先,要查看某个类是否存在,请使用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] =>
)
)
答案 1 :(得分:14)
我知道这个问题已经有了答案,但我想为我认为你的问题提供一个更现实的解决方案。如果我昨天有更多时间发表评论,我会发布这个。对不起,我没有。
听起来OP有一个模块系统,他需要知道在允许调用之前是否加载了特定模块。
首先,我想说使用命名空间只是简单地声明模块是IMO,滥用它们的用途。如果您遵循nameSpacing到字母的目的,您的结构可能看起来更像这样:
您的整个系统应该位于自己的命名空间中。我们称之为名称空间System
。然后,模块可能位于System\Module
命名空间下。然后,根据复杂性,每个模块可能在System\Module
下有一个名称空间。举例,System\Module\FOO
和System\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 );
}
}
);
另一种可能的方法是为具有特定功能的模块定义接口,以便在初始化模块时进行注册。但是,这意味着需要首先加载模块,并且可能会根据您的需要导致模块自身的问题。
这样做之后: