is it possible to get list of defined namespaces
HI there,
I was wondering if there is a way in php 5.3+ to get a list of defined namespaces within an application. so
if
file 1 has nam开发者_StackOverflow中文版espace FOO
and
file 2 has namespace BAR
Now if i include file 1 and file 2 in file 3 id like to know with some sort of function call that namespace FOO and BAR are loaded.
I want to achieve this to be sure an module in my application is loaded before checking if the class exists ( with is_callable ).
If this is not possible i'd like to know if there is a function to check if a specific namespace is defined, something like is_namespace().
Hope you get the idea. and what i'm trying to achieve
Firstly, to see if a class exists, used class_exists
.
Secondly, you can get a list of classes with namespace using get_declared_classes
.
In the simplest case, you can use this to find a matching namespace from all declared class names:
function namespaceExists($namespace) {
$namespace .= "\\";
foreach(get_declared_classes() as $name)
if(strpos($name, $namespace) === 0) return true;
return false;
}
Another example, the following script produces a hierarchical array structure of declared namespaces:
<?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);
Gives:
Array
(
[FirstNamespace] =>
[SecondNamespace] => Array
(
[FirstSubNamespace] =>
)
[ThirdNamespace] => Array
(
[FirstSubNamespace] =>
[SecondSubNamespace] =>
)
)
I know this question already has an answer, but I wanted to provide a more realistic solution to what I believe your problem is. Had I had more time yesterday when I made my comment I would have posted this. Sorry that I didn't.
It sounds like OP has a module system that he needs to know if a particular module is loaded prior to allowing a call to it.
First, I'd like to say that using namespaces simply to declare modules active is, IMO, abusing what they are for. If you follow the purpose of namespacing to the letter, your structure might look more like this:
Your entire system should be in its own namespace. Let's call that namespace System
. Then, modules would likely be under the System\Module
namespace. Then, depending on the complexity, it would be possible that each module might have a namespace under System\Module
. Taking your examples, System\Module\FOO
and System\Module\BAR
.
Now, let's get into making a module system that registers itself on load.
First, we need a place to register to. Let's call that System\Module\Registry
and, since there are likely to be a lot of different registries, it will implement the System\iRegistry
. For brevity, I'm only posting System\Module\Registry
. In all likelihood, it will also implement some sort of global consistency model, like a singleton, but I'm not showing that either. Here it is:
<?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.");
}
}
}
?>
Now, in each module you'd need to call this register function when the file is loaded. There are a couple of ways to do this. The first is to have some code in your module's namespace that run on load similar to typical proceedural code:
namespace System\Module\FOO
{
// Load this module
$system->module->register("FOO");
}
The above would mean code duplication though. You might also use autoload for this instead, that way the "registering" code is all in one place. Here's a very basic concept of doing that:
spl_autoload_register(
function ($className)
{
// Code to load files.
// Once loaded register our modules.
if( $namespace = "System\\Module" )
{
$system->module->register( $classname );
}
}
);
Another possible way of doing this would be to define an interface for modules with a specific function for registering when the module is initialized. This, however, means the module needs to be loaded first and might cause it's own issues depending on your needs.
After doing this:
- you have a consistent namespace for modules to live in
- you have a consistent interface which allows any module to know how to register itself
- you can easily expand the module or registry interfaces in the future for new things, while keeping your code clean and easy to understand.
- and, most importantly, you will know that your modules will actually declare that they are loaded and/or ready instead of relying on black magic to do it for you.
精彩评论