Получить пространство имен дочерних классов из суперкласса в PHP

Предполагая, что у меня есть следующие классы в разных файлах:

<?php namespace MyNS; class superclass { public function getNamespace(){ return __NAMESPACE__; } } ?> <?php namespace MyNS\SubNS; class childclass extends superclass { } ?> 

Если я создаю экземпляр «childclass» и вызываю getNamespace (), он возвращает «MyNS».

Есть ли способ получить текущее пространство имен из дочернего класса без повторного использования метода?

Я прибегал к созданию статической переменной пространства имен в каждом классе и ссылаюсь на нее с использованием super::$namespace но это просто не очень элегантно.

Solutions Collecting From Web of "Получить пространство имен дочерних классов из суперкласса в PHP"

__NAMESPACE__ – это константа времени компиляции, что означает, что она полезна только во время компиляции. Вы можете думать о нем как о макросе, который, когда вставил, заменит себя текущим пространством имен. Следовательно, нет способа получить __NAMESPACE__ в суперклассе, чтобы ссылаться на пространство имен дочернего класса. Вам придётся прибегнуть к какой-то переменной, которая назначается в каждом дочернем классе, как вы уже делаете.

В качестве альтернативы вы можете использовать отражение, чтобы получить имя пространства имен класса:

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

См. Руководство по PHP для получения дополнительной (незавершенной) документации. Обратите внимание, что вам нужно быть на PHP 5.3.0 или новее, чтобы использовать отражение.

Вы также можете сделать это в методе getNamespace ():

 return get_class($this); 

При вызове из детского класса результатом будет:

 MyNS\SubNS\childclass 

Если вы не хотите имя класса в конце, просто отрубите все от последнего \ до конца.

В моем случае мне нужно было создать метод в родительском классе, который может вызвать статический метод с помощью call_user_func() в каком-то подклассе. Если вы знаете полное имя класса, вы можете call_user_func() no problemo. Трюк состоял в том, чтобы вызвать статический метод в пространстве имен подкласса.

Таким образом, мы имеем

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

Теперь нам нужен метод в AbstractParent . Этот метод, вызванный из подкласса Foo , сможет вызвать Bar::doMe() , добавив его собственное пространство имен.

Вот как вы это делаете с динамическим вызовом:

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

Чтобы заставить его работать со статическим вызовом, замените get_class($this) на get_called_class()

Начиная с PHP 5.3 вы можете использовать get_called_class и некоторые строковые функции для достижения этого.

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

Надеюсь это поможет.

 /* 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 />"; } 

Отредактировано в ответ на Artur Bodera, чтобы добавить функциональность «звонок»

Вы также можете перезаписать метод getNamespace в своем дочернем классе с тем же кодом, что и в вашем суперклассе.

то вызов $ this-> getNamespace () в другом методе вашего суперкласса вернет пространство имен класса, соответствующего объекту.

 <?php namespace MyNS; class superclass { public function getNamespace(){ return __NAMESPACE__; } public function foo() { echo $this->getNamespace(); } } ?> <?php namespace MyNS\SubNS; class childclass extends \MyNS\superclass { public function getNamespace(){ return __NAMESPACE__; } } ?> A = new MyNS\superclass(); B = new MyNS\subNS\childclass(); A->foo() will display "MyNS" B->foo() will display "MyNS\SubNS"