2010-07-28 17 views
25

Cuando se define una función en un espacio de nombres,Llamar a una función de PHP se define en otro espacio de nombres sin el prefijo

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

debe especificar el espacio de nombres cuando se llama desde otro (o global) de espacio de nombres:

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

con las clases que puede emplear la "utilización" declaración para importar de manera efectiva una clase en el espacio de nombres actual [Editar:. pensé que podría "utilizar foo" para obtener las clases, pero al parecer no]

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

pero esto no funciona con funciones [y sería difícil de manejar dado cuántos hay]:

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

Puede crear un alias del espacio de nombres para hacer el prefijo más corto para escribir,

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

, pero ¿hay alguna forma de eliminar el prefijo por completo?

Antecedentes: Estoy trabajando en la biblioteca de coincidencias de Hamcrest que define muchas funciones de fábrica, y muchas de ellas están diseñadas para ser anidadas. Tener el prefijo de espacio de nombres realmente mata la legibilidad de las expresiones. Comparo

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

a

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

Respuesta

28

PHP 5.6 permitirá importar funciones con el use palabra clave:

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

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

Véase el RFC para más información: https://wiki.php.net/rfc/use_function

+2

Acabo de construir el 5.6.0-dev en Windows y lo probé.Parece funcionar bien, aunque debe importar cada función individualmente. – b01

+3

Esta es la respuesta correcta a esta pregunta. – user3640967

1

no sé una solución elegante , pero ...

Puede crear funciones de contenedor que encapsulan las funciones en el espacio de nombres externo. Esto le permitirá mantener su legibilidad del código ...

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

+0

Las funciones existentes ya son envolturas de conveniencia que llaman a la métodos de fábrica estáticos reales. Podría proporcionar una copia duplicada de este módulo sin el espacio de nombre y dejar que el usuario decida qué desea importar. El efecto sería el mismo y apostaría bastante fácil de automatizar. –

7

Mediante la adición de los cortes auxiliares se mencionan a continuación, puede importar todo, desde Hamcrest espacio de nombres de espacio de nombres actual llamando:

import_namespace('Hamcrest', __NAMESPACE__); 

Aquí están los cortes, function_alias funciona como http://www.php.net/manual/en/function.class-alias.php excepto si funciona en funciones:

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

} 

En combinación con nombre importador de espacio:

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

inventivo, pero terrible! – Evert

Cuestiones relacionadas