Получить пространство имен дочернего класса из суперкласса в PHP - PullRequest
27 голосов
/ 23 февраля 2010

При условии, что у меня есть следующие классы в разных файлах:

<?php
    namespace MyNS;

    class superclass {

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

<?php
    namespace MyNS\SubNS;

    class childclass extends superclass { }
?>

Если я создаю экземпляр "childclass" и вызываю getNamespace (), он возвращает "MyNS".

Есть ли способ получить текущее пространство имен от дочернего класса без повторного выделения метода?

Я прибег к созданию статической переменной $ namespace в каждом классе и обращаюсь к ней с помощью super::$namespace, но это не очень элегантно.

Ответы [ 6 ]

20 голосов
/ 23 февраля 2010

__NAMESPACE__ - постоянная времени компиляции, что означает, что она полезна только во время компиляции. Вы можете думать об этом как о макросе, который при вставке заменит себя текущим пространством имен. Следовательно, в суперклассе нет способа получить __NAMESPACE__ для ссылки на пространство имен дочернего класса. Вам придется прибегнуть к какой-то переменной, которая присваивается каждому дочернему классу, как вы уже делаете.

В качестве альтернативы вы можете использовать отражение, чтобы получить имя пространства имен класса:

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

См. руководство по PHP для получения дополнительной (незаконченной) документации. Обратите внимание, что для использования отражения вам необходимо использовать PHP 5.3.0 или более позднюю версию.

12 голосов
/ 28 мая 2010

Вы также можете сделать это в вашем методе getNamespace ():

return get_class($this);

При вызове из дочернего класса результат будет:

MyNS\SubNS\childclass

Если вам не нужно имя класса в конце, просто отрежьте все от последнего \ до конца.

4 голосов
/ 21 июля 2011

В моем случае мне нужно было создать метод в родительском классе, который может вызывать статический метод с 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()

3 голосов
/ 10 февраля 2014

Начиная с PHP 5.3, вы можете использовать get_called_class и некоторые строковые функции для достижения этой цели.

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

1 голос
/ 25 ноября 2013

Надеюсь, это поможет.

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

Отредактировано в ответ на Артура Бодера, чтобы добавить функциональность «вызова»

0 голосов
/ 13 мая 2014

Вы также можете перезаписать метод 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"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...