2010-07-28 10 views
25

Quando si definisce una funzione in uno spazio dei nomi,Chiamata di una funzione PHP definita in un altro spazio dei nomi senza il prefisso

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

è necessario specificare lo spazio dei nomi quando si chiama da un altro (o globale) dello spazio dei nomi:

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

Con le classi si possono utilizzare l ' "utilizzazione" dichiarazione per importare in modo efficace una classe nel namespace corrente [Edit:. ho pensato che si potrebbe "usare foo" per ottenere le classi, ma a quanto pare non]

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

, ma questo non funziona con le funzioni [e sarebbe ingombrante dato quanti ce ne sono]:

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

È possibile alias lo spazio dei nomi per rendere il prefisso più breve per digitare,

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

ma esiste un modo per rimuovere completamente il prefisso?

Sfondo: sto lavorando alla libreria di corrispondenza di Hamcrest che definisce molte funzioni di fabbrica e molte sono progettate per essere annidate. Avere il prefisso namespace uccide davvero la leggibilità delle espressioni. Paragono

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)) 
    ))); 

risposta

28

PHP 5.6 permette di importare le funzioni con la parola chiave use:

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

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

vedere la RFC per ulteriori informazioni: https://wiki.php.net/rfc/use_function

+2

Ho appena installato il 5.6.0-dev su Windows e l'ho provato.Sembra funzionare bene, anche se devi importare ciascuna funzione individualmente. – b01

+3

Questa è la risposta corretta a questa domanda. – user3640967

1

Non so una soluzione elegante , ma ...

È possibile creare funzioni wrapper che incapsulano le funzioni nello spazio dei nomi esterno. Questo vi permetterà di mantenere la leggibilità del codice ...

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

+0

Le funzioni esistenti sono già involucri di convenienza che chiamano la metodi di fabbrica statici reali. Potrei fornire una copia duplicata di questo modulo senza lo spazio dei nomi e lasciare che l'utente decida quale ha voluto importare. L'effetto sarebbe lo stesso e scommetterei abbastanza facilmente da automatizzare. –

7

Aggiungendo gli hack helper di seguito indicate, è possibile importare tutto da Hamcrest namespace per namespace corrente chiamando:

import_namespace('Hamcrest', __NAMESPACE__); 

Ecco hack, function_alias funziona come http://www.php.net/manual/en/function.class-alias.php meno che lavori sulle funzioni:

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 combinazione con il nome spazio importatore:

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, ma terribile! – Evert

Problemi correlati