代码之家  ›  专栏  ›  技术社区  ›  Alex Weber

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

  •  26
  • Alex Weber  · 技术社区  · 16 年前

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

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

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

    有没有办法不重新说明方法就从子类中获取当前名称空间?

    super::$namespace 但那感觉不太优雅。

    6 回复  |  直到 13 年前
        1
  •  21
  •   Håvard S    16 年前

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

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

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

    看见 the PHP manual 更多(未完成的)文档。请注意,您需要使用php5.3.0或更高版本才能使用反射。

        2
  •  15
  •   user171929    16 年前

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

    return get_class($this);
    

    MyNS\SubNS\childclass
    

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

        3
  •  4
  •   Artur Bodera    15 年前

    在我的例子中,我需要在父类中创建一个方法,该方法可以使用 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()

        4
  •  4
  •   Cryszon    12 年前

    从PHP5.3开始,您可以使用 get_called_class

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

        5
  •  1
  •   Chris    12 年前

    希望这有帮助。

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

        6
  •  0
  •   Freidhairick    12 年前

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