Возможно плохой дизайн; форсирование статического определения в наследовании классов в PHP - PullRequest
3 голосов
/ 11 декабря 2011

Я думаю, что, возможно, попал в стену из-за плохих дизайнерских решений.

Я работаю над иерархией классов, с абстрактной базой, из которой выходят несколько классов. Не вдаваясь в подробности того, почему функции экземпляров этих классов требуют наличия объекта «контекст» - текущего работающего объекта.

abstract class AbstractBase{

    protected static $_context;

    protected $_parent;

    public static function get_context(){
        return static::$_context;
    }

    protected static function set_context(self $context, &$previous = null){
        $previous = static::get_context();
        static::$_context = $context;
    }

    public function __construct(){
        $this->_parent = static::get_context();
    }

    public function do_something($callback){
        static::set_context($this, $previous);
        $callback();
        static::set_context($previous);
    }

}

class ConcreteOne extends AbstractBase{

}

class ConcreteTwo extends AbstractBase{

}

Это прекрасно работает, за исключением того, что ConcreteOne и ConcreteTwo необходимо отслеживать их собственный контекст - текущее определение приведет к тому, что любое изменение контекста любого наследуемого класса перезапишет AbstractBase::$_context. Это изменение достаточно легко осуществить:

class ConcreteOne extends AbstractBase{

    protected static $_context;

}

class ConcreteTwo extends AbstractBase{

    protected static $_context;

}

Теперь конкретные реализации будут управлять своими собственными контекстами. Это, однако, представляет собой небольшую проблему; любые клиентские классы, расширяющие базовый класс, будут иметь статический член с именем $_context.

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

Итак, я должен идти вперед или кто-то может предложить лучшее решение для управления "статическим" контекстом между экземплярами?


Примечание : я рассмотрел передачу объекта $context в качестве аргумента $callback, однако, поскольку ConcreteOne обратные вызовы могут создавать экземпляры объектов ConcreteTwo и вызывать их ( и наоборот, и любой другой наследуемый класс ), который может привести к тому, что большое количество объектов контекста необходимо будет передать в определенный момент времени - я не думаю, что это решение.

Ответы [ 2 ]

1 голос
/ 11 декабря 2011

Я собираюсь пойти дальше и опубликовать это как ответ, так как я верю, что это то, к чему вы работаете в конце.

Проблема, которую, я полагаю, вы замечаете, заключается в том, что у вас естьсвойство абстрактного класса $_context, которое настроено для хранения одного контекста, но для того, чтобы оно работало правильно, вам действительно нужна ссылка внутри / самим классом.Таким образом, свойство $_context в вашем примере на самом деле является ссылкой на контекст текущего объекта, а не отдельным контекстом для всех экземпляров классов, расширяющих ваш AbstractBase.

Это, конечно, неимеет смысл.Я бы посоветовал настроить ваш текущий статический $_context и использовать его в качестве хранилища для сохранения и извлечения ваших ссылок, возвращая уникальный идентификатор, когда контекст установлен, и помещая этот идентификатор в $this->context_id, чтобы объект мог продолжатьсячтобы получить его контекст по ссылке:

<?php

abstract class AbstractBase {
    protected static $_context;
    private $context_id;

    public static function setContext($context) {
        $context_id = uniqid(php_uname('n'), true);
        self::$_context[$context_id] = $context;
        return $context_id;
    }

    public function getContext() {
        return self::$_context[$this->context_id];
    }

    public function myPrint() {
        print_r($this);
        print_r(self::$_context);
    }
}

class test1 extends AbstractBase {
    public function __construct($context){
        $this->context_id = self::setContext($context);
    }
}

class test2 extends AbstractBase {
    public function __construct($context){
        $this->context_id = self::setContext($context);
    }
}

$test1 = new test1('this stuff');
$test2 = new test2('other stuff');

$test1->myPrint();
$test2->myPrint();

?>

http://codepad.org/1FlYkTN1

0 голосов
/ 11 декабря 2011

Это выглядит немного вынужденно. Я думаю, что «обычный» базовый класс, имеющий статические методы или имеющий статический объект, был бы лучшей стратегией.

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