在PHP中从超类获取子类命名空间

在PHP中从超类获取子类命名空间,php,inheritance,namespaces,Php,Inheritance,Namespaces,假设我在不同的文件中有以下类: <?php namespace MyNS; class superclass { public function getNamespace(){ return __NAMESPACE__; } } ?> <?php namespace MyNS\SubNS; class childclass extends superclass { } ?&g

假设我在不同的文件中有以下类:

<?php
    namespace MyNS;

    class superclass {

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

<?php
    namespace MyNS\SubNS;

    class childclass extends superclass { }
?>

如果我实例化“childclass”并调用getNamespace(),它将返回“MyNS”

是否有任何方法可以从子类获取当前名称空间,而无需重新声明该方法


我在每个类中创建了一个静态$namespace变量,并使用
super::$namespace
引用它,但这感觉不是很优雅。

\uuuu namespace\uuu
是一个编译时常量,这意味着它只在编译时有用。您可以将其视为一个宏,插入的宏将用当前名称空间替换自身。因此,无法在超类中获取
\uuuu NAMESPACE\uuu
,以引用子类的名称空间。您将不得不求助于在每个子类中分配的某种变量,就像您已经在做的那样

或者,您可以使用反射来获取类的命名空间名称:

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

有关更多(未完成的)文档,请参阅。请注意,您需要使用PHP 5.3.0或更高版本才能使用反射。

您也可以在getNamespace()方法中执行此操作:

从childclass调用时,结果将是:

MyNS\SubNS\childclass

如果你不想让类名在末尾,就把从最后一个\到结尾的所有内容都切掉。

在我的例子中,我需要在父类中创建一个方法,它可以在某些子类中使用
call\u user\u func()
调用静态方法。如果你知道完整的类名,你可以
调用\u user\u func()
没问题。诀窍是在子类的命名空间中调用静态方法

所以我们有

\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\u class($this)
替换为
get\u called\u 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 />";
}
/*第一个命名空间*/
名称空间MyNS{
类超类{
/*获取当前命名空间的函数
*如果$object为null,则返回
*类所在的类的命名空间
*方法存在,如果不为null,则返回
*调用的类的命名空间。
*/
公共静态函数get_命名空间($object=null){
如果($object!==null){
$tmp=($object!=“self”)和($get_调用的_类()!=get_类($object))?get_类($object):get_调用的_类();
$tmparr=爆炸(“\\”,$tmp);
$class=array_pop($tmparr);
返回联接(“\\”,$tmparr);
}否则{
返回_名称空间_;
}
}
公共静态函数get_current_namespace(){
返回self::get_名称空间(self);
}
公共函数调用静态方法($class\u name,$method\u name,$arguments=array()){
$class=“\\”$this->get\u名称空间($this)。“\\{$class\u name}”;
如果(方法_存在($class$method_name)){
if(count($arguments)>0)返回$class::$method\u name($arguments);
返回$class::$method_name();
}
返回“类({$class})中不存在方法({$Method_name})”;
}
公共函数调用用户方法($object,$method\u name,$arguments=array()){
如果(方法_存在($object,$method_name)){
if(count($arguments)>0)返回$object->$method\u name($arguments);
返回$object->$method_name();
}
}
}
类超类2扩展了超类{
公共静态函数foo(){
返回“超类2 foo”;
}
公共功能条(){
返回“超类2条”;
}
}
}
/*第二命名空间*/
名称空间MyNS\SubNS{
类childclass扩展\MyNS\superclass{}
类childclass2扩展\MyNS\superclass{
公共静态函数foo(){
返回“childclass2 foo”;
}
公共功能条(){
返回“childclass2 bar”;
}
}
}
/*返回到根命名空间*/
名称空间{
/*返回“MyNS”*/
echo\MyNS\superclass::get_namespace()。“
”; echo\MyNS\SubNS\childclass::get_namespace()。“
”; /*返回“MyNS”*/ echo\MyNS\superclass::get_current_namespace()。“
”; /*返回“MyNS\SubNS”*/ echo\MyNS\SubNS\childclass::get_current_namespace()。“
”; /*还是这样*/ $super=new\MyNS\superclass(); $child=new\MyNS\SubNS\childclass(); /*返回“MyNS”*/ echo$super->get_namespace()。“
”; echo$child->get_namespace()。“
”; /*返回“MyNS”*/ echo$super->get_名称空间($super)。“
”; /*返回“MyNS\SubNS”*/ echo$child->get_名称空间($child)。“
”; /*返回“超级类2 foo”*/ echo$super->call_static_方法(“superclass2”,“foo”)。“
”; /*返回“超类2条”*/ $super2=new\MyNS\superclass2(); echo$super->call_user_方法($super2,“bar”)。“
”; /*返回“超级类2 foo”*/ echo$child->call_static_方法(“childclass2”,“foo”)。“
”; /*返回“超类2条”*/ $child2=new\MyNS\SubNS\childclass2(); echo$child->call_user_方法($child2,“bar”)。“
”; }

根据Artur Bodera的要求进行编辑以添加“调用”功能

从PHP 5.3开始,您可以使用
get\u called\u class
和一些字符串函数来实现这一点


substr(get\u称为\u class(),0,strrpos(get\u称为\u class(),“\\”)

您还可以使用与超类相同的代码覆盖子类中的getNamespace方法

然后,在超类中的另一个方法中调用$this->getNamespace(),将返回与该对象对应的类的名称空间。
/* 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 />";
}
<?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"