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 namespace F
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:
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] =>
)
)