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

问题描述 投票:0回答:3

正如您在下面看到的,我有一个超类(文章)和两个子类。我希望每个子类都有一个静态数组来保存它的所有对象。

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()    
)

如果你问我,这看起来很相似,但第一个应该只包含报告,第二个应该只包含采访。

1。看起来只有一个数组,为什么只有一个数组?
2.我有一个同一类中的对象的静态容器,这是错误的编码吗? (有什么建议吗?)

我对 php 还很陌生,但有 java 背景。

php inheritance static subclass extend
3个回答
16
投票

所有内容都只进入一个数组,原因有两个:

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

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

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

    class Report extends Article { public static $articles = array(); } class Interview extends Article { public static $articles = array(); }
    
    
    如果您将静态变量声明视为在定义类时运行的代码,那么这实际上是有意义的。创建静态变量并为其分配一个空数组是在定义

    Article

     类时发生的。当定义 
    Interview
    Report
     类时,不会再发生这种情况。只有一次会分配一个空数组 - 只有一个共享变量。

  2. 您在

    self

     方法中使用 
    add_Object_To_Array()
     而不是 
    static

    • self::

       指的是它定义的类,因此由于您的 
      add_Object_To_Array()
       方法是在 
      Article
       类中定义的,因此它将引用 
      Article::$articles
       数组。

    • static::

       从 PHP 5.3 开始可用,指的是它被
      称为的类。这称为 后期静态绑定,并且将导致 add_Object_To_Array()
       引用 
      Report::$articles
      Interview::$articles
      ,具体取决于您调用它的对象的类型。

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

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

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

此解决方案使用

get_class()

 查找我们要存储的对象的类型,然后将其存储在父类中 - 以类名作为键的子数组中:

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());
    

0
投票
对于任何正在寻找替代解决方案的人来说,除了上述好的解决方案之外。 您可以使用PHP的后期静态绑定(

static::

),但您还需要在每个子类中单独定义变量(这将使它们独立)。

您可以使用这个:

abstract class Article { public static $articles = array(); public function add_Object_To_Array() { array_push(static::$articles, $this); } } class Report extends Article{ public static $articles = array(); } class Interview extends Article{ public static $articles = array(); }
然后当从每个子类调用

add_Object_To_Array()

时,它会将文章存储在不同的位置。

请参阅

后期静态绑定

© www.soinside.com 2019 - 2024. All rights reserved.