Подтвердить что ты не робот

Вызов функции PHP, определенной в другом пространстве имен без префикса

Когда вы определяете функцию в пространстве имен,

namespace foo {
    function bar() { echo "foo!\n"; }
    class MyClass { }
}

вы должны указать пространство имен при вызове его из другого (или глобального) пространства имен:

bar();          // call to undefined function \bar()
foo\bar();      // ok

С помощью классов вы можете использовать инструкцию "use" для эффективного импорта класса в текущее пространство имен [Edit: Я думал, что вы можете "использовать foo" для получения классов, но, по-видимому, нет.]

use foo\MyClass as MyClass;
new MyClass();  // ok, instantiates foo\MyClass

но это не работает с функциями [и будет громоздким, учитывая, сколько есть]:

use foo\bar as bar;
bar();          // call to undefined function \bar()

Вы можете псевдоним пространства имен, чтобы сделать префикс более коротким,

use foo as f;   // more useful if "foo" were much longer or nested
f\bar();        // ok

но есть ли способ полностью удалить префикс?

Справочная информация. Я работаю над библиотекой соответствия Hamcrest, которая определяет множество функций factory, и многие из них предназначены для вложенности. Наличие префикса пространства имен действительно убивает читаемость выражений. Сравнить

assertThat($names, 
    is(anArray(
        equalTo('Alice'), 
        startsWith('Bob'), 
        anything(), 
        hasLength(atLeast(12))
    )));

к

use Hamcrest as h;
h\assertThat($names, 
    h\is(h\anArray(
        h\equalTo('Alice'), 
        h\startsWith('Bob'), 
        h\anything(), 
        h\hasLength(h\atLeast(12))
    )));
4b9b3361

Ответ 1

PHP 5.6 позволит импортировать функции с ключевым словом use:

namespace foo\bar {
    function baz() {
        echo 'foo.bar.baz';
    }
}

namespace {
    use function foo\bar\baz;
    baz();
}

См. RFC для получения дополнительной информации: https://wiki.php.net/rfc/use_function

Ответ 2

Добавив вспомогательные хаки, упомянутые ниже, вы можете импортировать все из пространства имен Hamcrest в текущее пространство имен, вызывая:

import_namespace('Hamcrest', __NAMESPACE__);

Вот хаки, function_alias работает как http://www.php.net/manual/en/function.class-alias.php, за исключением того, что работает над функциями:

function function_alias ($original, $alias) {

  $args = func_get_args();
  assert('count($args) == 2', 'function_alias(): requires exactly two arguments');
  assert('is_string($original) && is_string($alias)', 'function_alias(): requires string arguments');

  // valid function name - http://php.net/manual/en/functions.user-defined.php
  assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][\\\\\\\\a-zA-Z0-9_\x7f-\xff]*$/\', $original) > 0',
"function_alias(): '$original' is not a valid function name");
  assert('preg_match(\'/^[a-zA-Z_\x7f-\xff][\\\\\\\\a-zA-Z0-9_\x7f-\xff]*$/\', $alias) > 0',
    "function_alias(): '$alias' is not a valid function name");

  $aliasNamespace = substr($alias, 0, strrpos($alias, '\\') !== false ? strrpos($alias, '\\') : 0);
  $aliasName = substr($alias, strrpos($alias, '\\') !== false ? strrpos($alias, '\\') + 1 : 0);
  $serializedOriginal = var_export($original, true);

  eval("
    namespace $aliasNamespace {
      function $aliasName () {
        return call_user_func_array($serializedOriginal, func_get_args());
      }
    }
  ");

}

В сочетании с импортером пространства имён:

function import_namespace ($source, $destination) {

  $args = func_get_args();
  assert('count($args) == 2', 'import_namespace(): requires exactly two arguments');
  assert('is_string($source) && is_string($destination)', 'import_namespace(): requires string arguments');

  // valid function name - http://php.net/manual/en/functions.user-defined.php
  assert('preg_match(\'/^([a-zA-Z_\x7f-\xff][\\\\\\\\a-zA-Z0-9_\x7f-\xff]*)?$/\', $source) > 0',
    "import_namespace(): '$destination' is not a valid namespace name");
  assert('preg_match(\'/^([a-zA-Z_\x7f-\xff][\\\\\\\\a-zA-Z0-9_\x7f-\xff]*)?$/\', $destination) > 0',
    "import_namespace(): '$source' is not a valid namespace name");

  foreach(get_declared_classes() as $class)
    if (strpos($class, $source . '\\') === 0)
      class_alias($class, $destination . ($destination ? '\\' : '') . substr($class, strlen($source . '\\')));

  $functions = get_defined_functions();
  foreach(array_merge($functions['internal'], $functions['user']) as $function)
    if (strpos($function, $source . '\\') === 0)
      function_alias($function, $destination . ($destination ? '\\' : '') . substr($function, strlen($source . '\\')));
}

Ответ 3

Я не знаю элегантного решения, но...

Вы можете создавать функции-обертки, которые инкапсулируют функции во внешнем пространстве имен. Это позволит вам сохранить читаемость кода...

function assertThat($x, $y) { return h\assertThat($x, $y); }