I was wondering if it was possible to determine what the current namespace was when the function was being called. I have this function declaration:
<?php
namespace Site\Action;
function add ($hook, $function) {
/**
* determine the namespace this was called from because
* __NAMESPACE__ is "site\action" :(
*/
if (is_callable($function))
call_user_func($function);
}
?>
And on another file:
<?php
namespace Foo;
function bar () {
}
?>
And let's say I have this as my procedural code:
<?php
namespace Foo;
Site\Action\add('hookname', 'bar');
?>
It would make sense to assume that Bar
in this case was intended to resolve as Foo\bar
since that was the namespace it was called from.
That was a long explanation so again, is it possible to determine the active namespace where Site\Action\add()
was called from?
Thanks in advance.
What you are looking for is : ReflectionFunctionAbstract::getNamespaceName
If you want to know where you're coming from debug_backtrace() is your friend.
The following should solve your puzzle:
function backtrace_namespace()
{
$trace = array();
$functions = array_map(
function ($v) {
return $v['function'];
},
debug_backtrace()
);
foreach ($functions as $func) {
$f = new ReflectionFunction($func);
$trace[] = array(
'function' => $func,
'namespace' => $f->getNamespaceName()
);
}
return $trace;
}
Just call it from anywhere to see the backtrace.
I modified your "procedural" code file as follows:
namespace Foo;
function bar ()
{
var_export(backtrace_namespace());
}
/** The unasked question: We need to use the fully qualified name currently. */
function go()
{
\Site\Action\add('hookname', 'Foo\\bar');
}
go();
The Result from including this file will be the following on stdout:
array (
0 =>
array (
'function' => 'backtrace_namespace',
'namespace' => '',
),
1 =>
array (
'function' => 'Foo\\bar',
'namespace' => 'Foo',
),
2 =>
array (
'function' => 'call_user_func',
'namespace' => '',
),
3 =>
array (
'function' => 'Site\\Action\\add',
'namespace' => 'Site\\Action',
),
4 =>
array (
'function' => 'Foo\\go',
'namespace' => 'Foo',
),
)
Now for bonus points the answer to the hidden question:
How do I resolve the calling namespace to avoid using fully qualified function name as argument?
The following will allow you to call the function as you intended:
Site\Action\add('hookname', 'bar');
Without getting the dreaded:
Warning: call_user_func() expects parameter 1 to be a valid callback, function 'bar' not found or invalid function name
So before you redesign try this on for size:
namespace Site\Action;
function add($hook, $function)
{
$trace = backtrace_namespace();
$prev = (object) end($trace);
$function = "$prev->namespace\\$function";
if (is_callable($function))
call_user_func($function);
}
I see no reason why debug_backtrace
should not be used, this is what it is there for.
nJoy!
If you were using closures instead of static functions you can always ask the reflection API
namespace A;
$closure = function($word = 'hello')
{
return $word;
};
...
$r = new ReflectionFunction($closure);
print $r->getNamespaceName();
i don't know if i'm missing something, but with this:
http://php.net/manual/en/reflectionclass.getnamespacename.php, i think that you can get namespace of the object you are using.