2010-07-28 5 views
25

Wenn Sie eine Funktion in einem Namensraum zu definieren,Aufruf eine PHP-Funktion in einem anderen Namensraum definiert ohne das Präfix

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

Sie den Namespace angeben muß, wenn sie von einem anderen (oder global) Namespace Aufruf:

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

Mit Klassen, die Sie einsetzen können, die „Verwendung“ Anweisung effektiv eine Klasse in den aktuellen Namensraum zu importieren [Edit:. Vielleicht haben Sie, um die Klassen zu bekommen „foo verwenden“ könnten, aber anscheinend nicht]

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

aber mit Funktionen funktioniert nicht [und wäre unhandlich gegeben, wie viele es sind]:

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

Sie den Namespace Alias ​​kann das Präfix kürzer zu machen, geben Sie

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

Aber gibt es eine Möglichkeit, das Präfix vollständig zu entfernen?

Hintergrund: Ich arbeite an der Hamcrest-Matching-Bibliothek, die viele Factory-Funktionen definiert und viele von ihnen sind verschachtelt. Wenn das Namespace-Präfix verwendet wird, wird die Lesbarkeit der Ausdrücke wirklich aufgehoben. Vergleichen

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

zu

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

Antwort

28

PHP 5.6 können Funktionen mit dem use Schlüsselwort importieren:

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

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

Siehe RFC für weitere Informationen: https://wiki.php.net/rfc/use_function

+2

Ich habe gerade den 5.6.0-dev auf Windows gebaut und es ausprobiert.Scheint gut zu funktionieren, obwohl Sie jede Funktion einzeln importieren müssen. – b01

+3

Dies ist die richtige Antwort auf diese Frage. – user3640967

1

Ich weiß nicht, eine elegante Lösung, aber ...

Sie können Wrapper-Funktionen erstellen, die die Funktionen im externen Namespace einzukapseln. So können Sie Ihre Lesbarkeit des Codes halten ...

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

+0

Die vorhandenen Funktionen sind bereits Convenience-Wrapper, der den Anruf echte statische Fabrikmethoden. Ich könnte eine Kopie dieses Moduls ohne den Namensraum zur Verfügung stellen und den Benutzer entscheiden lassen, welche sie importieren wollten. Der Effekt wäre der gleiche und ich würde wetten, dass das Automatisieren ziemlich einfach ist. –

7

Durch das Hinzufügen der Helfer Hacks unten erwähnt, alles aus hamcrest Namensraum zu aktuellen Namensraum durch den Aufruf importieren:

import_namespace('Hamcrest', __NAMESPACE__); 

Hier sind die Hacks, arbeitet function_alias wie http://www.php.net/manual/en/function.class-alias.php außer wenn Arbeiten an Funktionen:

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 Kombination mit dem Namen Raum Importeur:

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

Erfinderisch, aber schrecklich! – Evert

Verwandte Themen