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\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
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)) )));
PHP 5.6 will allow to import functions with the use
keyword:
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
By adding the helper hacks mentioned below, you can import everything from Hamcrest namespace to 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 if 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 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 . '\\'))); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With