Предполагая, что у меня есть следующие классы в разных файлах:
<?php namespace MyNS; class superclass { public function getNamespace(){ return __NAMESPACE__; } } ?> <?php namespace MyNS\SubNS; class childclass extends superclass { } ?>
Если я создаю экземпляр «childclass» и вызываю getNamespace (), он возвращает «MyNS».
Есть ли способ получить текущее пространство имен из дочернего класса без повторного использования метода?
Я прибегал к созданию статической переменной пространства имен в каждом классе и ссылаюсь на нее с использованием super::$namespace
но это просто не очень элегантно.
__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"