2010-02-23 9 views
25

Ich habe die folgenden Klassen in verschiedenen Dateien Unter der Annahme:Get Kind-Klasse-Namespace von übergeordneten Klasse in PHP

<?php 
    namespace MyNS; 

    class superclass { 

     public function getNamespace(){ 
      return __NAMESPACE__; 
     } 
    } 
?> 

<?php 
    namespace MyNS\SubNS; 

    class childclass extends superclass { } 
?> 

Wenn ich "Child" instanziiert und rufen getNamespace() it "myNS" zurückgibt.

Gibt es eine Möglichkeit, den aktuellen Namespace von der untergeordneten Klasse abzurufen, ohne die Methode erneut zu deklarieren?

Ich habe eine statische $ Namespace-Variable in jeder Klasse erstellen und referenzieren mit super::$namespace, aber das fühlt sich einfach nicht sehr elegant.

+0

Auch wenn Sie nicht ausdrücklich danach gefragt werden, könnten Sie sich auch für das Schlüsselwort 'namespace' interessieren, http://doc.php.net/language.namespaces.nsconstants, z. 'echo namespace \ MyClass :: myFunction();' – VolkerK

+0

Danke, ich bin mir dessen bewusst, aber leider funktioniert es in dieser Situation nicht! :) –

Antwort

19

__NAMESPACE__ ist eine Kompilierzeitkonstante, was bedeutet, dass sie nur zur Kompilierzeit nützlich ist. Sie können sich das als ein Makro vorstellen, das sich durch den aktuellen Namespace ersetzt. Daher gibt es keine Möglichkeit, __NAMESPACE__ in einer Superklasse zu erhalten, um auf den Namespace einer Kindklasse zu verweisen. Sie müssen auf eine Art Variable zurückgreifen, die in jeder Kindklasse zugewiesen ist, wie Sie es bereits tun.

Als Alternative können Sie Reflektion verwenden, um den Namespace-Namen einer Klasse zu erhalten:

$reflector = new ReflectionClass('A\\Foo'); // class Foo of namespace A 
var_dump($reflector->getNamespaceName()); 

Siehe the PHP manual für mehr (unvollendet) Dokumentation. Beachten Sie, dass Sie PHP 5.3.0 oder höher verwenden müssen, um Reflektionen zu verwenden.

+0

Danke, das macht Sinn, ich habe hier total reflektionslos übersehen! –

+0

Sehr nützlich. Vielen Dank ! – Caio

12

Sie können dies auch in Ihrem getNamespace() -Methode:

return get_class($this); 

Wenn von Child genannt, wird das Ergebnis sein:

MyNS\SubNS\childclass 

Wenn Sie die Klasse wollen nicht Namen auf das Ende, hacken Sie einfach alles vom letzten bis zum Ende ab.

4

In meinem Fall musste ich eine Methode in der Elternklasse erstellen, die eine statische Methode mit call_user_func() in einer Unterklasse aufrufen kann. Wenn Sie den vollständigen Klassennamen kennen, können Sie call_user_func() kein Problem. Der Trick bestand darin, eine statische Methode im Namespace der Unterklasse aufzurufen.

So haben wir das heißt

\MyTools\AbstractParent 
\Something\Else\Foo extends \MyTools\AbstractParent 
\Something\Else\Bar extends \MyTools\AbstractParent 

Wir haben nun ein Verfahren in AbstractParent müssen. Diese Methode, die von der Unterklasse Foo aufgerufen wird, kann Bar::doMe() aufrufen, indem sie ihren eigenen Namensraum vorstellt.

Hier ist, wie Sie es mit dynamischem Aufruf tun:

namespace MyTools; 
abstract class AbstractParent { 
    public static method doMe(){} 

    public function callSomethingStaticInClass($class){ 
     // current namespace IS NOT MyTools 
     // so you cannot use __NAMESPACE__ 
     $currentClass = get_class($this); 
     $refl = new ReflectionClass($currentClass); 
     $namespace = $refl->getNamespaceName(); 

     // now we know what the subclass namespace is... 
     // so we prefix the short class name 
     $class = $namespace . '\\' . $class; 
     $method = 'doMe'; 

     return call_user_func(array($class, $method)); 
    } 

}; 

namespace Something\Else; 
class Foo extends AbstractParent { } 
class Bar extends AbstractParent { } 

$foo = new Foo(); 
$foo->callSomethingStaticInClass('Bar'); 

Um es mit einem statischen Aufruf ersetzen funktioniert get_class($this) mit get_called_class()

+0

Dies sollte die Antwort sein. – Tek

1

Hoffnung, das hilft.

/* First Namespace */ 
namespace MyNS { 
    class superclass { 
     /* Functions to get the current namespace 
     * If $object is null then return the 
     * namespace of the class where the 
     * method exists, if not null, return 
     * the namespace of the class called. 
     */ 
     public static function get_namespace($object = null) { 
      if($object !== null) { 
       $tmp = (($object != "self") && (get_called_class() != get_class($object))) ? get_class($object) : get_called_class(); 
       $tmparr = explode("\\", $tmp); 
       $class = array_pop($tmparr); 
       return join("\\", $tmparr); 
      } else { 
       return __NAMESPACE__; 
      } 
     } 
     public static function get_current_namespace() { 
      return self::get_namespace(self); 
     } 

     public function call_static_method($class_name, $method_name, $arguments = array()) { 
      $class = "\\" . $this->get_namespace($this) . "\\{$class_name}"; 
      if(method_exists($class, $method_name)) { 
       if(count($arguments) > 0) return $class::$method_name($arguments); 
       return $class::$method_name(); 
      } 
      return "Method ({$method_name}) Does not exist in class ({$class})"; 
     } 

     public function call_user_method($object, $method_name, $arguments = array()) { 
      if(method_exists($object, $method_name)) { 
       if(count($arguments) > 0) return $object->$method_name($arguments); 
       return $object->$method_name(); 
      } 
     } 
    } 

    class superclass2 extends superclass { 
     public static function foo() { 
      return "superclass2 foo"; 
     } 
     public function bar() { 
      return "superclass2 bar"; 
     } 
    } 
} 

/* Second Namespace */ 
namespace MyNS\SubNS { 
    class childclass extends \MyNS\superclass { } 

    class childclass2 extends \MyNS\superclass { 
     public static function foo() { 
      return "childclass2 foo"; 
     } 
     public function bar() { 
      return "childclass2 bar"; 
     } 
    } 
} 

/* Back to Root Namespace */ 
namespace { 
    /* Returns 'MyNS' */ 
    echo \MyNS\superclass::get_namespace() . "<br />"; 
    echo \MyNS\SubNS\childclass::get_namespace() . "<br />"; 

    /* Returns 'MyNS' */ 
    echo \MyNS\superclass::get_current_namespace() . "<br />"; 

    /* Returns 'MyNS\SubNS' */ 
    echo \MyNS\SubNS\childclass::get_current_namespace() . "<br />"; 


    /* Or this way */ 


    $super = new \MyNS\superclass(); 
    $child = new \MyNS\SubNS\childclass(); 

    /* Returns 'MyNS' */ 
    echo $super->get_namespace() . "<br />"; 
    echo $child->get_namespace() . "<br />"; 

    /* Returns 'MyNS' */ 
    echo $super->get_namespace($super) . "<br />"; 

    /* Returns 'MyNS\SubNS' */ 
    echo $child->get_namespace($child) . "<br />"; 

    /* Returns 'superclass2 foo' */ 
    echo $super->call_static_method("superclass2", "foo") . "<br />"; 

    /* Returns 'superclass2 bar' */ 
    $super2 = new \MyNS\superclass2(); 
    echo $super->call_user_method($super2, "bar") . "<br />"; 

    /* Returns 'superclass2 foo' */ 
    echo $child->call_static_method("childclass2", "foo") . "<br />"; 

    /* Returns 'superclass2 bar' */ 
    $child2 = new \MyNS\SubNS\childclass2(); 
    echo $child->call_user_method($child2, "bar") . "<br />"; 
} 

Herausgegeben in Reaktion auf Artur Bodera 'nennen' hinzuzufügen Funktionalität

3

Ab PHP 5.3 Sie get_called_class und einige String-Funktionen verwenden können, um dies zu erreichen.

substr(get_called_class(), 0, strrpos(get_called_class(), "\\"))

+0

Dies ist die richtige und beste Antwort. Kann nicht einfacher sein, und es funktioniert – Andrew

0

Sie können auch die getNamespace Methode in Ihrer Kind-Klasse mit dem gleichen Code wie in der Superklasse überschreiben.

Dann ruft $ this-> getNamespace() in einer anderen Methode in Ihrer Oberklasse den Namespace der Klasse zurück, die dem Objekt entspricht.

Verwandte Themen