Get child class namespace from superclass in PHP

后端 未结 6 1041
南旧
南旧 2020-12-09 02:24

Assuming I have the following classes in different files:



        
相关标签:
6条回答
  • 2020-12-09 02:43

    In my case, I needed to create a method in parent class, that can call a static method with call_user_func() in some subclass. If you know the full class name, you can call_user_func() no problemo. The trick was to call a static method in the subclass' namespace.

    So we have i.e.

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

    We now need a method in AbstractParent. This method called from subclass Foo will be able to call Bar::doMe() by prepending its own namespace.

    Here is how you do it with dynamic call:

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

    To make it work with a static call replace get_class($this) with get_called_class()

    0 讨论(0)
  • 2020-12-09 02:49

    You can also do this in your getNamespace() method:

    return get_class($this);
    

    When called from childclass, the result will be:

    MyNS\SubNS\childclass
    

    If you don't want the class name on the end, just chop off everything from the last \ to the end.

    0 讨论(0)
  • 2020-12-09 02:50

    As of PHP 5.3 you can use get_called_class and some string functions to achieve this.

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

    0 讨论(0)
  • 2020-12-09 02:58

    You can also overwrite the getNamespace method in your child class with the same code as in your superclass.

    then, calling $this->getNamespace() in another method in your superclass will return the namespace of the class corresponding to the object.

    <?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"
    
    0 讨论(0)
  • 2020-12-09 02:59

    __NAMESPACE__ is a compile time constant, meaning that it is only useful at compile time. You can think of it as a macro which where inserted will replace itself with the current namespace. Hence, there is no way to get __NAMESPACE__ in a super class to refer to the namespace of a child class. You will have to resort to some kind of variable which is assigned in every child class, like you are already doing.

    As an alternative, you can use reflection to get the namespace name of a class:

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

    See the PHP manual for more (unfinished) documentation. Note that you'll need to be on PHP 5.3.0 or later to use reflection.

    0 讨论(0)
  • 2020-12-09 03:01

    Hope this helps.

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

    Edited in response to Artur Bodera to add 'call' functionality

    0 讨论(0)
提交回复
热议问题