可能设计不佳;在PHP中继承类时强制静态定义

时间:2011-12-11 08:40:52

标签: php oop inheritance static

我认为由于糟糕的设计决定,我可能会碰壁。

我正在开发一个类层次结构,它有一个抽象基础,几个类可以从中扩展。在没有深入了解原因的“细节”的情况下,这些类的实例函数需要“上下文”对象可用 - 当前操作对象。

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{

}

这很好,除了ConcreteOneConcreteTwo需要跟踪他们自己的上下文 - 当前定义将导致任何继承类的任何上下文更改都会覆盖AbstractBase::$_context。这种变化相当容易实现:

class ConcreteOne extends AbstractBase{

    protected static $_context;

}

class ConcreteTwo extends AbstractBase{

    protected static $_context;

}

现在具体实现将管理自己的上下文。然而,这提出了一个问题;任何扩展基类的客户端类都需要一个名为$_context的静态成员。

这给我带来了糟糕的设计,但话又说回来,我的鼻子还不是最尖锐的。我想知道我是否已经在这里找到了一条糟糕的道路,最重要的是,如果我继续沿着这条路走下去或者中途改变它。

那么,我应该继续前进,还是有人可以提出更好的解决方案来跨实例管理“静态”上下文?


注意:我已经考虑将$context对象作为参数传递给$callback,但是因为ConcreteOne回调可能会创建实例,并调用,ConcreteTwo对象(,反之亦然,以及任何其他继承类)可能导致需要在给定时间传递大量上下文对象 - 我不知道认为这是一个解决方案。

2 个答案:

答案 0 :(得分:1)

我将继续发布这个作为答案,因为我相信这是你最终努力的目标。

我相信你发现的问题是你有抽象类属性$_context,它被设置为存储单个上下文,但为了使其正常工作,你真的需要在/中的引用由实际的班级本身。因此,在您的示例中,$_context属性实际上是对当前对象上下文的引用,而不是扩展AbstractBase的所有实例化类的单个上下文。

这当然没有意义。我建议的是调整当前的静态$_context并将其用作存储来保存和检索引用,在设置上下文时返回唯一ID并将该ID放入$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

答案 1 :(得分:0)

看起来有点强迫。我认为具有静态方法的“常规”基类 - 或者具有静态对象将是更好的策略。