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

时间:2022-04-29 23:54:43

Assuming I have the following classes in different files:

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

<?php
    namespace MyNS;

    class superclass {

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

<?php
    namespace MyNS\SubNS;

    class childclass extends superclass { }
?>

If I instantiate "childclass" and call getNamespace() it returns "MyNS".

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

Is there any way to get the current namespace from the child class without redeclaring the method?

是否有方法在不重新声明方法的情况下从子类获取当前名称空间?

I've resorted to creating a static $namespace variable in each class and referencing it using super::$namespace but that just doesn't feel very elegant.

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

6 个解决方案

#1


19  

__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.

__NAMESPACE__是一个编译时常量,这意味着它只在编译时有用。您可以将它看作一个宏,在这个宏中,insert将用当前的名称空间替换自己。因此,无法在超类中获取__NAMESPACE__来引用子类的名称空间。您将不得不求助于在每个子类中分配的某种变量,就像您已经在做的那样。

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.

有关更多(未完成的)文档,请参阅PHP手册。注意,您需要在PHP 5.3.0或以后使用反射。

#2


12  

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

您还可以在getNamespace()方法中进行此操作:

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.

如果不希望类名出现在末尾,只需从最后一个\到末尾删除所有内容。

#3


4  

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.

在我的例子中,我需要在父类中创建一个方法,该方法可以在某些子类中调用带有call_user_func()的静态方法。如果您知道完整的类名,那么可以调用_user_func()。诀窍是在子类的名称空间中调用一个静态方法。

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.

我们现在需要一个抽象父类的方法。这个从Foo子类调用的方法将能够通过预挂它自己的名称空间来调用Bar:::doMe()。

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()

要使它在静态调用中工作,可以使用get_class($this)替换get_called_class()

#4


3  

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

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

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

substr(get_called_class(),0,大小写敏感(get_called_class(),“\ \”))

#5


1  

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

根据Artur Bodera编辑的功能,添加“调用”功能

#6


0  

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

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

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

然后,在父类的另一个方法中调用$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"

#1


19  

__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.

__NAMESPACE__是一个编译时常量,这意味着它只在编译时有用。您可以将它看作一个宏,在这个宏中,insert将用当前的名称空间替换自己。因此,无法在超类中获取__NAMESPACE__来引用子类的名称空间。您将不得不求助于在每个子类中分配的某种变量,就像您已经在做的那样。

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.

有关更多(未完成的)文档,请参阅PHP手册。注意,您需要在PHP 5.3.0或以后使用反射。

#2


12  

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

您还可以在getNamespace()方法中进行此操作:

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.

如果不希望类名出现在末尾,只需从最后一个\到末尾删除所有内容。

#3


4  

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.

在我的例子中,我需要在父类中创建一个方法,该方法可以在某些子类中调用带有call_user_func()的静态方法。如果您知道完整的类名,那么可以调用_user_func()。诀窍是在子类的名称空间中调用一个静态方法。

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.

我们现在需要一个抽象父类的方法。这个从Foo子类调用的方法将能够通过预挂它自己的名称空间来调用Bar:::doMe()。

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()

要使它在静态调用中工作,可以使用get_class($this)替换get_called_class()

#4


3  

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

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

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

substr(get_called_class(),0,大小写敏感(get_called_class(),“\ \”))

#5


1  

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

根据Artur Bodera编辑的功能,添加“调用”功能

#6


0  

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

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

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

然后,在父类的另一个方法中调用$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"