调用在另一个命名空间中定义的没有前缀的 PHP 函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3358099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 09:27:53  来源:igfitidea点击:

Calling a PHP function defined in another namespace without the prefix

phpfunctionnamespaces

提问by David Harkness

When you define a function in a namespace,

在命名空间中定义函数时,

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

you must specify the namespace when calling it from another (or global) namespace:

从另一个(或全局)命名空间调用它时,您必须指定命名空间:

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

With classes you can employ the "use" statement to effectively import a class into the current namespace [Edit: I thought you could "use foo" to get the classes, but apparently not.]

对于类,您可以使用“use”语句将类有效地导入当前命名空间 [编辑:我认为您可以“使用 foo”来获取类,但显然不是。]

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

but this doesn't work with functions [and would be unwieldy given how many there are]:

但这不适用于函数[并且考虑到有多少会很笨拙]:

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

You can alias the namespace to make the prefix shorter to type,

您可以为命名空间设置别名以使前缀更短以便键入,

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

but is there any way to remove the prefix entirely?

但是有没有办法完全删除前缀?

Background: I'm working on the Hamcrest matching library which defines a lot of factory functions, and many of them are designed to be nested. Having the namespace prefix really kills the readability of the expressions. Compare

背景:我正在研究 Hamcrest 匹配库,它定义了许多工厂函数,其中许多被设计为嵌套。拥有命名空间前缀真的会扼杀表达式的可读性。相比

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

to

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

回答by Matthieu Napoli

PHP 5.6 will allow to import functions with the usekeyword:

PHP 5.6 将允许使用use关键字导入函数:

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

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

See the RFC for more information: https://wiki.php.net/rfc/use_function

有关更多信息,请参阅 RFC:https: //wiki.php.net/rfc/use_function

回答by luka8088

By adding the helper hacks mentioned below, you can import everything from Hamcrest namespace to current namespace by calling:

通过添加下面提到的帮助程序,您可以通过调用将 Hamcrest 命名空间中的所有内容导入到当前命名空间:

import_namespace('Hamcrest', __NAMESPACE__);

Here are the hacks, function_alias works like http://www.php.net/manual/en/function.class-alias.phpexcept if works on functions:

以下是技巧,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());
      }
    }
  ");

}

In combination with namespace importer:

结合命名空间导入器:

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 . '\')));
}

回答by Borealid

I don't know an elegantsolution, but...

我不知道一个优雅的解决方案,但是......

You can create wrapper functions that encapsulate the functions in the external namespace. This will let you keep your code readability...

您可以创建将函数封装在外部命名空间中的包装函数。这将使您保持代码的可读性......

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

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