Определите, в каком пространстве имен была вызвана функция - PullRequest
7 голосов
/ 15 декабря 2011

Мне было интересно, можно ли определить текущее пространство имен при вызове функции. У меня есть это объявление функции:

<?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);
}
?>

И в другом файле:

<?php
namespace Foo;
function bar () {
}
?>

И скажем, у меня есть этот процедурный код:

<?php
namespace Foo;
Site\Action\add('hookname', 'bar');
?>

Имеет смысл предположить, что Bar в этом случае предназначалось для разрешения как Foo\bar, поскольку это было пространство имен, из которого оно было вызвано.

Это было длинное объяснение, так что, можно ли определить активное пространство имен, откуда был вызван Site\Action\add()?

Заранее спасибо.

Ответы [ 3 ]

4 голосов
/ 20 сентября 2012

Что вы ищете: ReflectionFunctionAbstract :: getNamespaceName

Если вы хотите знать, откуда вы пришли debug_backtrace () ваш друг.

Следующее должно решить вашу загадку:

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;
}

Просто позвоните из любой точки мира, чтобы увидеть след. Я изменил ваш файл процедурного кода следующим образом:

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();

Результат от включения этого файла будет следующим на стандартный вывод:

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',
    ),
)

Теперь за бонусные баллы ответ на скрытый вопрос:

Как разрешить вызывающее пространство имен, чтобы избежать использования полного имени функции в качестве аргумента?

Следующее позволит вам вызвать функцию, как вы и предполагали:

 Site\Action\add('hookname', 'bar');

Без страха:

Предупреждение: call_user_func () ожидает, что параметр 1 будет допустимым обратным вызовом, функция 'bar' не найдена или недопустимое имя функции

Так что перед тем, как сделать редизайн, попробуйте это для размера:

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);
}

Я не вижу причин, по которым debug_backtrace не следует использовать, вот для чего он нужен.

NJoy!

1 голос
/ 30 августа 2012

Если вы использовали замыкания вместо статических функций, вы всегда можете задать API отражения

namespace A;
$closure = function($word = 'hello')
{
    return $word;
};

...

$r = new ReflectionFunction($closure);
print $r->getNamespaceName();
0 голосов
/ 15 декабря 2011

я не знаю, что-то упустил, но с этим:

http://php.net/manual/en/reflectionclass.getnamespacename.php, я думаю, что вы можете получить пространство имен используемого вами объекта.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...