PHP:子类静态继承 - 子共享静态变量?

时间:2013-07-13 18:06:13

标签: php inheritance static subclass extend

如下所示,我有一个超类(文章)和两个子类。我希望每个子类都有一个静态数组,它可以保存所有它的对象。

abstract class Article
{
    public static $articles = array(); // Variable for storing all the objects of each sub-class.

    public function add_Object_To_Array()
    {       
        array_push(self::$articles, $this);
    }
}

class Report extends Article{}
class Interview extends Article{}

- 制作两个Report对象并将它们添加到数组中:

$tmp = new Report();
$tmp->add_Object_To_Array();

$tmp = new Report();
$tmp->add_Object_To_Array();

- 制作两个Interview对象并将它们添加到数组中:

$tmp = new Interview();
$tmp->add_Object_To_Array();

$tmp = new Interview();
$tmp->add_Object_To_Array();

print_r(Report::$articles);
print_r(Interview::$articles);

- 以上脚本吐出了两个数组:

Array
(
    [0] => Report Object()

    [1] => Report Object()

    [2] => Interview Object()

    [3] => Interview Object()   
)
Array
(
    [0] => Report Object()

    [1] => Report Object()

    [2] => Interview Object()

    [3] => Interview Object()    
)

如果你问我,它看起来非常相似,但第一个应该只包含Reports,第二个只包含Interviews。

1。似乎只有一个数组,为什么只有一个数组?
2。我在同一个类中有一个静态容器对象,这是不好的编码? (有任何建议吗?)

我对php很新,但是有一个java背景。

2 个答案:

答案 0 :(得分:11)

由于两个原因,一切都只进入一个数组:

  1. $articles属性仅在Article类中定义。

    如果习惯了非静态属性,静态类属性的继承方式与预期的方式不同。虽然它们 可用于子类,但它们仍然引用父类的单个变量 - 导致您在这里看到两个子类共享同一个数组的行为。

    防止这种情况的唯一方法是在每个子类中定义一个单独的数组,如下所示:

    class Report extends Article {
        public static $articles = array();
    }
    class Interview extends Article {
        public static $articles = array();
    }
    

    如果您将静态变量声明视为在定义类时运行的代码,那么这实际上是有意义的。在定义Article类时,会创建静态变量并为其分配空数组。定义InterviewReport类时,不会再次发生这种情况。只有一次空数组被分配 - 只有一个共享变量。

  2. 您在self方法中使用add_Object_To_Array()而不是static

    • self::是指定义它的类,因为add_Object_To_Array()类定义了Article方法,所以它会引用Article::$articles } array。

    • static::从PHP 5.3开始可用,并引用名为的类。这称为Late Static Binding,会导致add_Object_To_Array()引用Report::$articlesInterview::$articles,具体取决于您调用它的对象的类型。

    此代码将引用我们在第一步中声明的两个数组:

    public function add_Object_To_Array() {
        array_push(static::$articles, $this);
    }
    

答案 1 :(得分:3)

我认为我会提出一种替代解决方案,可以稍微改变您的设计,但不需要在每个子类中使用静态定义。根据您的使用情况,这可能是也可能不是第一个解决方案的更好选择。

此解决方案使用get_class()查找我们正在存储的对象的类型,然后将其存储在父类中 - 在由classname键入的子数组中:

abstract class Article
{
    public static $articles = array();

    public function add_Object_To_Array()
    {
        // get the actual class of the current object
        $class = get_class($this);
        // define an empty subarray for this class if we haven't seen it before
        if (!isset(self::$articles[$class])) {
            self::$articles[$class] = array();
        }
        // add this object to the appropriate subarray
        array_push(self::$articles[$class], $this);
    }
}
class Report extends Article{}
class Interview extends Article{}

上面的代码不使用后期静态绑定,因此它适用于任何PHP版本,而不仅仅是PHP 5.3 +。

当您使用原始示例运行此版本时,您将获得如下输出:

Array
(
    [Report] => Array
        (
            [0] => Report Object
                (
                )

            [1] => Report Object
                (
                )

        )

    [Interview] => Array
        (
            [0] => Interview Object
                (
                )

            [1] => Interview Object
                (
                )

        )

)

如果你有PHP 5.3或更高版本,你可以进一步扩展它并使用get_called_class()函数来定义一个getInstances()静态方法(在Article类中)这样:

public static function getInstances()
{
    $class = get_called_class();
    // return isset(self::$articles[$class]) ? self::$articles[$class] : array();
    if (isset(self::$articles[$class])) {
        return self::$articles[$class];
    } else {
        return array();
    }
}

然后你可以在你的例子中调用这个方法,如下所示:

print_r(Report::getInstances());
print_r(Interview::getInstances());