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

Posted

技术标签:

【中文标题】从 PHP 中的超类获取子类命名空间【英文标题】:Get child class namespace from superclass in PHP 【发布时间】:2011-01-20 00:20:57 【问题描述】:

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

<?php
    namespace MyNS;

    class superclass 

        public function getNamespace()
            return __NAMESPACE__;
        
    
?>

<?php
    namespace MyNS\SubNS;

    class childclass extends superclass  
?>

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

有什么方法可以在不重新声明方法的情况下从子类获取当前命名空间?

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

【问题讨论】:

虽然没有特别要求,但您可能也对 namespace 关键字感兴趣,doc.php.net/language.namespaces.nsconstants 例如echo namespace\MyClass::myFunction(); 谢谢,我知道但不幸的是它在这种情况下不起作用! :) 【参考方案1】:

您还可以使用与超类中相同的代码覆盖子类中的 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"

【讨论】:

【参考方案2】:

从 PHP 5.3 开始,您可以使用 get_called_class 和一些字符串函数来实现这一点。

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

【讨论】:

这是正确且最佳的答案。再简单不过了,而且很有效【参考方案3】:

希望这会有所帮助。

/* 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 而编辑以添加“呼叫”功能

【讨论】:

【参考方案4】:

就我而言,我需要在父类中创建一个方法,该方法可以在某些子类中调用带有call_user_func() 的静态方法。如果您知道完整的班级名称,您可以call_user_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_class($this) 替换为 get_called_class()

【讨论】:

这应该是答案。【参考方案5】:

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

return get_class($this);

从子类调用时,结果为:

MyNS\SubNS\childclass

如果您不希望最后的类名,只需将最后一个 \ 到末尾的所有内容都砍掉即可。

【讨论】:

【参考方案6】:

__NAMESPACE__ 是编译时常量,意味着它只在编译时有用。您可以将其视为一个宏,插入的位置将用当前命名空间替换自身。因此,没有办法让超类中的__NAMESPACE__ 引用子类的命名空间。您将不得不求助于在每个子类中分配的某种变量,就像您已经在做的那样。

作为替代方案,您可以使用反射来获取类的命名空间名称:

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

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

【讨论】:

谢谢,有道理,我在这里完全忽略了使用反射!

以上是关于从 PHP 中的超类获取子类命名空间的主要内容,如果未能解决你的问题,请参考以下文章

子类方法的PHP命名空间范围?

使用命名空间从 XML 响应中获取 PHP 数组

PHP的 Final关键字类(文件)的加载和命名空间

说说PHP中的命名空间相关概念

C# - 在共享命名空间中跨文件使用命名空间

从 C# 2.0 中的 dll 获取命名空间、类名