Calling a PHP function defined in another namespace without a prefix

When you define a function in the namespace,

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

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

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

With classes, you can use the โ€œuseโ€ statement to efficiently import the class into the current namespace [Edit: I thought you could โ€œuse fooโ€ to get classes, but apparently not.]

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

but this does not work with functions [and will be cumbersome given how many there are]:

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

You can namespace alias to make the prefix shorter,

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

but is there a way to completely remove the prefix?

Reference Information. I am working on a Hamcrest mapping library that defines many factory functions, and many of them are for nesting. Having a namespace prefix really kills the readability of expressions. Compare

 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)) ))); 
+23
function php namespaces
Jul 28 2018-10-22T00:
source share
3 answers

PHP 5.6 allows you to import functions with the use keyword:

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

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

+25
Jan 05 '14 at 13:11
source share

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

 import_namespace('Hamcrest', __NAMESPACE__); 

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

 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 conjunction with a 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 . '\\'))); } 
+7
Feb 12 '13 at 18:14
source share

I do not know an elegant solution, but ...

You can create wrapper functions that encapsulate functions in the external namespace. This will allow you to maintain code readability ...

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

+1
Jul 28 2018-10-22T00:
source share



All Articles