Вызов статического метода в PHP 5.3 Синглтон-метод позднего статического связывания - PullRequest
1 голос
/ 22 сентября 2011

У меня есть абстрактный класс, который содержит эти методы:

<?php
public static function getInstance() {
    $me = get_called_class();
    if (!isset(self::$_instances[$me])) {
        $ref = new ReflectionClass($me);
        self::$_instances[$me] = $reflection_object->newInstance();
        self::$_instances[$me]->init();
    }
    return self::$_instances[$me];
}

public function __construct() {
    $me = get_class($this);
    if(isset(self::$_instances[$me])) {
        throw new Exception('The singleton class has already been instantiated!');
    } else {
        self::$_instances[$me] = $this;
        $this->_className = $me;
    }
}

Это работает точно так, как я и ожидал, когда создавал экземпляры в синглетах сиблингов. У меня возникла проблема при попытке получить экземпляр из дочернего класса, который не использует один и тот же суперкласс.

Моя трассировка стека:

Fatal error: Call to undefined method Keywords_AdminMenu_OptionsTable::init() in D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-content\plugins\LocalGiant_WPF\library\LocalGiant\Module\Abstract.php on line 149

Call Stack:
    0.0012     331664   1. {main}() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-admin\admin.php:0
    0.7772    3224864   2. do_action() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-admin\admin.php:151
    0.7774    3225792   3. call_user_func_array() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-includes\plugin.php:405
    0.7774    3225808   4. Keywords_AdminMenu->showMenu() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-includes\plugin.php:405
    0.7796    3227016   5. Keywords_AdminMenu_View::showMenu() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-content\plugins\LocalGiant_WPF\modules\Keywords\AdminMenu.php:29
    0.7821    3240776   6. Keywords_AdminMenu_OptionsTable->prepareItems() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-content\plugins\LocalGiant_WPF\modules\Keywords\AdminMenu\View.php:25
    0.7822    3241824   7. LocalGiant_Module_Abstract->getInstance() D:\webroot\domains\dev.slbmeh.com\htdocs\wordpress\wp-content\plugins\LocalGiant_WPF\modules\Keywords\AdminMenu\OptionsTable.php:90

Метод init () является абстрактным методом в суперклассе Singleton. Класс Keywords_AdminMenu_OptionsTable является подклассом класса из отдельного набора библиотек, WP_List_Table из WordPress.

Разбитая копия таблицы класса Keywords_AdminMenu_Options выглядит следующим образом:

<?php
class Keywords_AdminMenu_OptionsTable extends WP_List_Table {

    public function __construct(){
        global $status, $page;

        //Set parent defaults
        parent::__construct( array(
            'singular'  => 'module',
            'plural'    => 'modules',
            'ajax'      => false
        ) );

    }

    function prepareItems() {

        /* SNIP - Prepare my SQL query. */

        $moduleDatabase = Database_Module::getInstance();

        $current_page = $this->get_pagenum();

        $keywords = $moduleDatabase->simpleQuery($sql, $moduleLoader->getMyNamespace());

        /* SNIP - Handle my SQL data. */

    }
}

Содержимое WP_List_Table находится здесь: http://core.trac.wordpress.org/browser/tags/3.2.1//wp-admin/includes/class-wp-list-table.php

1 Ответ

2 голосов
/ 22 сентября 2011

Оказывается, в моем коде getInstance не был объявлен статическим.Этот фрагмент кода дает немного больше понимания того, как статические привязки влияют на привязки.

<code><pre><?php

class Singleton_Super {

    protected static $_instances = array();
    protected $_className;

    public function singletonSuperTest() {

        $getCalled = get_called_class();
        $getClass  = get_class($this);
        $getName   = $this->_className;

        echo "\nSingleton_Super::singletonSuperTest()\n";
        echo "\tget_called_class() = $getCalled\n";
        echo "\tget_class(\$this) = $getClass\n";
        echo "\t_className() = $getName\n";

    }

    public function whatsMyName() {
        echo "\nSingleton_Super::whatsMyName()\n\t$this->_className\n";
    }

    public static function getInstance() {
        $me = get_called_class();
        echo "\nSingleton_Super::getInstance()\n\tget_called_class() = $me\n";
        if (!isset(self::$_instances[$me])) {
            $ref = new ReflectionClass($me);
            self::$_instances[$me] = $ref->newInstance();
        }
        return self::$_instances[$me];
    }

    public function __construct() {
        $me = get_class($this);
        echo "\nSingleton_Super::__construct()\n\tget_called_class() = $me\n";
        if(isset(self::$_instances[$me])) {
            throw new Exception("The Singleton class, '$me', has already been instantiated.");
        } else {
            self::$_instances[$me] = $this;
            $this->_className = $me;
        }
    }

    public function __clone() {
        trigger_error("Cloning is not allowed.", E_USER_ERROR);
    }

    public function __wakeup() {
        trigger_error("Unserializing is not allowed.", E_USER_ERROR);
    }

}

class Singleton_Child extends Singleton_Super {

    public function singletonTest() {

        $getCalled = get_called_class();
        $getClass  = get_class($this);
        $getName   = $this->_className;

        echo "\nSingleton_Child::singletonTest()\n";
        echo "\tget_called_class() = $getCalled\n";
        echo "\tget_class(\$this) = $getClass\n";
        echo "\t_className() = $getName\n";

    }

}

class Outer_Concrete_Super {

    protected $_className;

    public function __construct() {
        $me = get_class($this);
        $this->_className = $me;
        echo "\nOuter_Concrete_Super::__construct()\n\tget_class(\$this) = $me\n";
    }

    public function whatsMyName() {
        echo $this->_className;
    }

    public function concreteSuperTest() {

        $getCalled = get_called_class();
        $getClass  = get_class($this);
        $getName   = $this->_className;

        echo "\nOuter_Concrete_Super::concreteSuperTest()\n";
        echo "\tget_called_class() = $getCalled\n";
        echo "\tget_class(\$this) = $getClass\n";
        echo "\t_className() = $getName\n";

    }

    public function superUseSingletonChild() {
        $singleton = Singleton_Child::getInstance();
        $singleton->singletonTest();
    }

}

class Outer_Concrete_Child extends Outer_Concrete_Super {

    public function concreteTest() {

        $getCalled = get_called_class();
        $getClass  = get_class($this);
        $getName   = $this->_className;

        echo "\nOuter_Concrete_Super::concreteSuperTest()\n";
        echo "\tget_called_class() = $getCalled\n";
        echo "\tget_class(\$this) = $getClass\n";
        echo "\t\$_className = $getName\n";

    }

    public function bigTest() {
        $singleton = Singleton_Child::getInstance();
        $singleton->whatsMyName();
        $singleton->singletonSuperTest();
        $singleton->singletonTest();
    }

}

echo "\n*****************************\n";
echo   "*        Constructors       *\n";
echo   "*****************************\n\n";

$singleP = Singleton_Super::getInstance();
$singleC = Singleton_Child::getInstance();
$outerP = new Outer_Concrete_Super;
$outerC = new Outer_Concrete_Child;

echo "\n*****************************\n";
echo   "* Third Party Class Testing *\n";
echo   "*****************************\n\n";

$outerP->concreteSuperTest();
$outerC->concreteSuperTest();
$outerC->concreteTest();
$outerC->bigTest();

echo "\n*****************************\n";
echo   "*         Singleton         *\n";
echo   "*****************************\n\n";

$singleP->whatsMyName();
$singleP->singletonSuperTest();
$singleC->whatsMyName();
$singleC->singletonSuperTest();
$singleC->singletonTest();

?>

Возвращает результат:

*****************************
*        Constructors       *
*****************************


Singleton_Super::getInstance()
        get_called_class() = Singleton_Super

Singleton_Super::__construct()
        get_called_class() = Singleton_Super

Singleton_Super::getInstance()
        get_called_class() = Singleton_Child

Singleton_Super::__construct()
        get_called_class() = Singleton_Child

Outer_Concrete_Super::__construct()
        get_class($this) = Outer_Concrete_Super

Outer_Concrete_Super::__construct()
        get_class($this) = Outer_Concrete_Child

*****************************
* Third Party Class Testing *
*****************************


Outer_Concrete_Super::concreteSuperTest()
        get_called_class() = Outer_Concrete_Super
        get_class($this) = Outer_Concrete_Super
        _className() = Outer_Concrete_Super

Outer_Concrete_Super::concreteSuperTest()
        get_called_class() = Outer_Concrete_Child
        get_class($this) = Outer_Concrete_Child
        _className() = Outer_Concrete_Child

Outer_Concrete_Super::concreteSuperTest()
        get_called_class() = Outer_Concrete_Child
        get_class($this) = Outer_Concrete_Child
        $_className = Outer_Concrete_Child

Singleton_Super::getInstance()
        get_called_class() = Singleton_Child

Singleton_Super::whatsMyName()
        Singleton_Child

Singleton_Super::singletonSuperTest()
        get_called_class() = Singleton_Child
        get_class($this) = Singleton_Child
        _className() = Singleton_Child

Singleton_Child::singletonTest()
        get_called_class() = Singleton_Child
        get_class($this) = Singleton_Child
        _className() = Singleton_Child

*****************************
*         Singleton         *
*****************************


Singleton_Super::whatsMyName()
        Singleton_Super

Singleton_Super::singletonSuperTest()
        get_called_class() = Singleton_Super
        get_class($this) = Singleton_Super
        _className() = Singleton_Super

Singleton_Super::whatsMyName()
        Singleton_Child

Singleton_Super::singletonSuperTest()
        get_called_class() = Singleton_Child
        get_class($this) = Singleton_Child
        _className() = Singleton_Child

Singleton_Child::singletonTest()
        get_called_class() = Singleton_Child
        get_class($this) = Singleton_Child
        _className() = Singleton_Child

Где, если вы изменитеПривязка getInstance от static вы получаете в результате:

*****************************
*        Constructors       *
*****************************


Singleton_Super::getInstance()
        get_called_class() = Singleton_Super

Singleton_Super::__construct()
        get_called_class() = Singleton_Super

Singleton_Super::getInstance()
        get_called_class() = Singleton_Child

Singleton_Super::__construct()
        get_called_class() = Singleton_Child

Outer_Concrete_Super::__construct()
        get_class($this) = Outer_Concrete_Super

Outer_Concrete_Super::__construct()
        get_class($this) = Outer_Concrete_Child

*****************************
* Third Party Class Testing *
*****************************


Outer_Concrete_Super::concreteSuperTest()
        get_called_class() = Outer_Concrete_Super
        get_class($this) = Outer_Concrete_Super
        _className() = Outer_Concrete_Super

Outer_Concrete_Super::concreteSuperTest()
        get_called_class() = Outer_Concrete_Child
        get_class($this) = Outer_Concrete_Child
        _className() = Outer_Concrete_Child

Outer_Concrete_Super::concreteSuperTest()
        get_called_class() = Outer_Concrete_Child
        get_class($this) = Outer_Concrete_Child
        $_className = Outer_Concrete_Child

Singleton_Super::getInstance()
        get_called_class() = Outer_Concrete_Child

Outer_Concrete_Super::__construct()
        get_class($this) = Outer_Concrete_Child
Outer_Concrete_Child

Fatal error:  Call to undefined method Outer_Concrete_Child::singletonSuperTest() in C:\inetpub\vhosts\BetterOffLocal.com\httpdocs\wp-content\plugins\LocalGiant_WPF\Singleton-Test.php on line 128

Надеюсь, этот ответ кому-нибудь поможет.Или, по крайней мере, дает представление о том, как решить эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...