【问题标题】:Static counter of subclass instances in PHPPHP中子类实例的静态计数器
【发布时间】:2020-09-15 13:08:39
【问题描述】:

我知道一种向类添加静态计数器以计算该类实例数的模式

class Vehicle
{
  private static $_count=0;

  public static function getCount() {
    return self::$_count;
  }

  public function __construct()
  {
    self::$_count++;
  }
}

我想做的是向 Vehicle 添加几个子类并独立计算这些子类的实例

class Bike extends Vehicle
{
   ...
}

class Car extends Vehicle 
{
   ...
}

所以调用Bike::getCount()Car::getCount() 将分别得到Bikes 和Cars 的数量

如果没有

这可能吗
  • 在子类中重复代码?
  • 在超类中设置某种以类名为键的计数数组?

【问题讨论】:

  • 明确违反单一责任原则。类不得计算自身的实例。创建另一个类,该类将包含任何项目的集合。

标签: php inheritance static


【解决方案1】:

您可以在父类中保留一个计数数组,而不仅仅是一个整数,使用static:class 进行索引。这将引用当前实例的类名,与 self:: 不同,后者始终引用正在使用它的类。

class Vehicle
{
  private static $counts = [];

  public static function getCount()
  {
      return self::$counts[static::class];
  }

  public function __construct()
  {
      // Using a reference here to avoid undefined-index notices
      $target =& self::$counts[static::class];
      $target++;
  }
}

class Bike extends Vehicle {}

new Bike;
var_dump(Bike::getCount());
// int(1)

完整演示:https://3v4l.org/Qibd7

我也同意@u_mulder 的评论,即这是一种不寻常的模式。类定义应该只关注单个实例的属性,而不是存储全局状态。维护一个实例集合(即使在一个普通的 PHP 数组中)意味着您可以独立计算它们。但这取决于你。

【讨论】:

  • 酷,我在问题中谈到了这一点,但感谢您花时间编写代码。这实际上比我想象的要整洁得多,值得思考!我也不知道那个参考技巧
  • @Arth Ha,是的,这是我完全错过的问题的唯一部分。很高兴它至少部分有用。我想我的问题是——你为什么不想那样做呢?对我来说,这似乎是自然的解决方案。
【解决方案2】:

很大程度上取决于您在哪里定义计数以及如何访问它。如果基类中有 1 个计数,则只有 1 个计数。如果您在每个类中都有一个计数,那么您需要知道如何访问正确的值。使用selfstatic 讨论更多What is the difference between self::$bar and static::$bar in PHP?

class Vehicle
{
    protected static $_count=0;

    public static function getCount() {
        return static::$_count;
    }

    public function __construct($type, $year)
    {
        // Access the count in the current class (Bike or Car).
        static::$_count++;
        // Access the count in this class
        self::$_count++;
    }
}

class Bike extends Vehicle
{
    protected static $_count=0;
}

class Car extends Vehicle
{
    protected static $_count=0;
}

这两者都有,并且在构造函数中,它同时递增它们。这意味着总共有所有车辆和每种类型...

echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
$a = new Car("a", 1);
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;
$a = new Bike("a", 1);
echo "Vehicle::getCount()=".Vehicle::getCount().PHP_EOL;
echo "Car::getCount()=".Car::getCount().PHP_EOL;
echo "Bike::getCount()=".Bike::getCount().PHP_EOL;

给出(虽然不是很清楚)...

Vehicle::getCount()=0
Car::getCount()=0
Bike::getCount()=0
Vehicle::getCount()=1
Car::getCount()=1
Bike::getCount()=0
Vehicle::getCount()=2
Car::getCount()=1
Bike::getCount()=1

【讨论】:

  • 谢谢!我是否认为如果有人实例化了 Vehicle 抽象以避免奇怪的重复计数是否有意义?
  • 如果永远不需要创建类的实例,那么将其定义为抽象会强制执行它。这仅取决于您的设计和使用方式。
  • static::$_count++ 类的构造函数中的static::$_count++ 语句被称为Late Static Binding
  • 似乎如果一个或多个实例由于某种原因未设置,计数将变得不准确。我还没有真正尝试过它,所以我不确定。如果是这样,也许析构函数中的减量会处理它。
  • @Don'tPanic,维护这种结构可能很复杂。任何跟踪对象的方法都需要管理对象的创建和删除。这意味着它们只存在于内存中,因此它们的生命周期可能很短。
猜你喜欢
  • 2022-06-29
  • 1970-01-01
  • 1970-01-01
  • 2016-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多