Code speaks better than words:
namespaces.php:
<?php
namespace foo;
use foo\models;
class factory
{
public static function create($name)
{
/*
* Note 1: FQN works!
* return call_user_func("\\foo\\models\\$name::getInstance");
*
* Note 2: direct instantiation of relative namespaces works!
* return models\test::getInstance();
*/
// Dynamic instantiation of relative namespaces fails: class 'models\test' not found
return call_user_func("models\\$name::getInstance");
}
}
namespace foo\models;
class test
{
public static $instance;
public static function getInstance()
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
public function __construct()
{
var_dump($this);
}
}
namespace_test.php:
<?php
require_once 'namespaces.php';
foo\factory::create('test');
As commented, if I use the full-qualified name inside call_user_func()
it works as expected, but if I use relative namespaces it says the class was not found – but direct instantiations works. Am I missing something or its weird by design?
You have to use the fully qualified classname in callbacks.
See Example #3 call_user_func()
using namespace name
<?php
namespace Foobar;
class Foo {
static public function test() {
print "Hello world!\n";
}
}
call_user_func(__NAMESPACE__ .'\Foo::test'); // As of PHP 5.3.0
call_user_func(array(__NAMESPACE__ .'\Foo', 'test')); // As of PHP 5.3.0
I believe this is because call_user_func
is a function from the global scope, executing the callback from the global scope as well. In any case, see first sentence.
Also see the note aboveExample #2 Dynamically accessing namespaced elements which states
One must use the fully qualified name (class name with namespace prefix).
In current versions of PHP, the way you have it is the way it is -- when using a string to reference a classname, it needs to be fully qualified with it's complete namespace. It's not great, but that's the way it is.
In the forthcoming PHP v5.5, they will include a feature to address this, by providing a new Classname::class
syntax, which you can use instead of putting the FQN classname in a string.
For more info on this, please see the relevant PHP RFC page here: https://wiki.php.net/rfc/class_name_scalars
Your code would look something like this:
return call_user_func([models\$name::class,"getInstance"]);
That may not be exact; I don't have a copy of 5.5 to test with to confirm. But either way, the new syntax will make things a lot better for use cases like yours.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With