PHP上的类实例?

PHP上的类实例?,php,Php,我不知道它叫什么,我相信它是实例 class Monster { private $monsters = array(); public function __construct() { self::monsters[] = $this; } public function __destruct() { array_splice(self::monsters, array_search($this, self::monsters)

我不知道它叫什么,我相信它是实例

class Monster {
    private $monsters = array();
    public function __construct() {
       self::monsters[] = $this;
    }

    public  function __destruct() {
        array_splice(self::monsters, array_search($this, self::monsters), 1 );
    }

    public static function getTotalHp() {
         $total = 0;
         foreach(self::monsters as $monster) {
            $total += $monster->getHp();
         }
         return $total;
    }    
}
假设我们有一个“怪物”类。此类应包含“健康”值。在创建类时将其设置为“5”。它还应该包含每个怪物的唯一ID值

我会这样想:

$monster_1 = new Monster(); //sets monster ID to 1
$monster_2 = new Monster(); //sets monster ID to 2
$monster_3 = new Monster(); //sets monster ID to 3
$monsters = array();
$totalHP = 0;
foreach($monsters as $monster) {
    $totalHP += $monster->getHp();
}
所以,假设我想计算所有怪物的总生命值

$totalHp = $monster_1->getHp() + $monster_2->getHp() + $monster_3->getHp();
它也可以工作,但是如果我添加一个名为
$monster_4
的新怪物会怎么样呢。我必须手动将其添加到$totalHp计算中

我可以制作一个数组而不是
$monster
变量,并用foreach计算$totalHp-但它看起来很奇怪

我不知道其他语言是如何做到的

有没有其他方法来归档这个


顺便说一句,我正试图弄明白“游戏”背后的逻辑。您创建了一个怪物类,每个怪物都使用这个类作为实例。我的解决方案肯定会起作用,但我不确定这是否是一种黑客式的归档方式。

您可以使用一个对象作为怪物的容器,并使用它来跟踪您:

class MonsterContainer
{
    private $monsters = array();

    public function __construct()
    {
       // do stuff   
    }   

    public function addMonster(Monster $monster)
    {
        $this->monsters[] = $monster;   
    }

    public function totalMonstersHP()
    {
        $hp = 0;
        foreach ($this->monsters as $monster)
        {
            $hp += $monster->getHp()
        }
        return $hp;
    }
}

$monster_1 = new Monster(); 
$monster_2 = new Monster(); 
$monster_3 = new Monster(); 

$container = new MonsterContainer();
$container->addMonster(monster_1);
$container->addMonster(monster_2);
$container->addMonster(monster_3);
echo $container->totalMonstersHP();

首先,它们被称为对象实例,就像在面向对象的编程中一样

其次,没有什么能阻止你创建一个怪物阵列(看起来并不奇怪):

$monsters = array(
    new Monster(),
    new Monster(),
    new Monster(),
    new Monster()
);

foreach($monsters as $monster) {
    $totalHP += $monster->hp;
}
关于唯一ID,这应该是
怪物工厂的责任,也就是说,怪物应该分配一个ID,它不应该分配给它自己,而应该分配给它。在创建怪物时,类似这样的操作:

new Monster(4); //ID is 4

谁跟踪它?其他人,而不是怪物。

我支持alexn,使用数组存储类实例(是的,这是正确的术语)非常好


然后,您可以使用
foreach
计算总HP。

创建MonstersCollection类,该类将包含方法
getNewMonster()
getTotalHP()

伪代码:

class MonstersCollection
{
   private $Monsters;

   public function getNewMonster()
   {
       $Monster=new Monster();
       $this->monsters[]=$Monster;
       return $Monster;
    }

   //and you know how to write method to get total HP :)
}

您可以创建一个
$monsters
数组,如下所示:

$monster_1 = new Monster(); //sets monster ID to 1
$monster_2 = new Monster(); //sets monster ID to 2
$monster_3 = new Monster(); //sets monster ID to 3
$monsters = array();
$totalHP = 0;
foreach($monsters as $monster) {
    $totalHP += $monster->getHp();
}
然后,每次您想要添加怪物时,都要执行以下操作:

$monsters[] = new Monster();
然后,您可以在阵列中循环以获得总生命值,如下所示:

$monster_1 = new Monster(); //sets monster ID to 1
$monster_2 = new Monster(); //sets monster ID to 2
$monster_3 = new Monster(); //sets monster ID to 3
$monsters = array();
$totalHP = 0;
foreach($monsters as $monster) {
    $totalHP += $monster->getHp();
}

在循环之后,
$totalHP
将包含您阵列中所有怪物的总生命值。

也许您可以在同一怪物类中创建一个新类或函数 在构造函数中调用,每次创建类时
它调用一个增加的全局变量。

创建一个助手类,该类包含一组怪物,可能是一个怪物团队类

class Monster {
     ...
}

class MonsterTeam {
    private $_monsters = [];

    public function addMonster(Monster &$monster) {
        array_push($this->_monsters, $monster);
    }

    public function getTotalHp() {
        $hp = 0;

        foreach ($this->_monsters as $monster) {
            $hp += $monster->getHp();
        }

        return $hp;
    }
}


$team = new MonsterTeam();

$monsterA = new Monster();
$team->addMonster($monsterA);

$monsterB = new Monster();
$team->addMonster($monsterB);

echo "Total HP: " . $team->getTotalHp();

您可以创建观察者模式,该模式可以在Monster实例化时自动更新集中对象中的totalHp属性

但在怪物类中,更快/更简单的方法是这样的:

class Monster {

   ...
   private $hp = 5;
   private static $totalHp = 0;
   ...

   public function getHp() {
       return $this->hp;
   }

   public function __construct(...) {
       ...
       self::totalHp += $this->getHp();
       ...
   }

   public function __destruct(...) {
       ...
       self::totalHp -= $this->getHp();
       ...
   }

   ...

   public static function getTotalHp() {
       return self::totalHp;
   }

   /**
    * Provide negative number to reduce HP or positive to increase HP.
    */
   public function alterHp($hp) {
       $this->hp += $hp;
       self::totalHp += $hp;
   }
}
然后,要获得当前的HP总值,您必须在客户端代码中执行以下操作:

$totalHp = Monster::getTotalHp();

你可以创建一个收集工厂;它将负责创造新的怪物。将两个类融合在一起通常不是我的事情,但我喜欢这样一个事实,即我可以使构造函数私有:)

它使用两个静态变量(我想是glorified global),一个用于怪物id,另一个用于怪物集合,使用
SplObjectStorage

需要迭代所有怪物的方法使用
each()
方法,因此可以在类之外定义所需的任何逻辑

class Monster
{
  private $id;
  public $health;

  private static $instances;
  private static $nextid = 1;

  // private constructor
  private function __construct($id)
  {
    $this->id = $id;
    $this->health = 5;
  }

  public static function create()
  {
    if (!self::$instances) {
      self::$instances = new SplObjectStorage;
    }
    $o = new self(self::$nextid++);
    self::$instances->attach($o);

    return $o;
  }

  public static function remove($o)
  {
    if (!self::$instances) { return; }
    self::$instances->detach($o);
  }

  // iterate over all objects
  public static function each($cb)
  {
    if (!self::$instances) { return; }
    foreach (self::$instances as $o) {
      $cb($o);
    }
  }
}
小用法示例

$m1 = Monster::create();
$m2 = Monster::create();

$total_health = 0;
Monster::each(function(Monster $m) use (&$total_health) {
  $total_health += $m->health;
});
echo "Total health: $total_health\n";

类跟踪其实例是很常见的

class Monster {
    private $monsters = array();
    public function __construct() {
       self::monsters[] = $this;
    }

    public  function __destruct() {
        array_splice(self::monsters, array_search($this, self::monsters), 1 );
    }

    public static function getTotalHp() {
         $total = 0;
         foreach(self::monsters as $monster) {
            $total += $monster->getHp();
         }
         return $total;
    }    
}


你可以用
eval()
来做,但这会很麻烦。阵列似乎是你的最佳选择,我想说,随它去吧。不要使用eval(),永远不要。将所有怪物存储在阵列中是一个完美的解决方案。@OZ_u这就是为什么我说它会很有黑客味。@OZ_u经典的货物崇拜编程。如果你从来没有使用过脚本语言和编译语言的区别,那么你就犯了严重的错误。Meme编码和不理解用例(正确工作的正确工具)并不太专业。这就是方法!Maby
类怪物扩展敌人
它违反了入侵。相同。这是一个全局变量。不是这样的。我已经更新了我的答案,以展示一种你们可能会觉得更吸引人的替代方式。所以,你们制作了一个奇特的数组?这不是一种优雅的方法,至少,你们需要将
\u construct
设为私有,这样其他人就不能制造怪物了。@JuanMendes同意,在比约恩的答案中有更正确的代码-这里只是一个例子来说明这个想法。不,不要使用全局变量。计算ID不是Monster类的责任。与John Conde的回答相同,我对此投了赞成票,但它很脆弱,如果
getHp()
发生变化怎么办?最好跟踪所有实例,并在调用getTotalHp时为所有实例调用
getHp()
。这是一个快速代码示例。我不打算在这里实现整个应用程序。理想情况下,getHp()应该只作为$hp属性的getter。没有其他内容。现在totalHp仅在hp更改时更新。这确保了我们拥有精确的totalHp,而无需一次又一次地运行循环。我不知道怎么做。totalHp属性在整个程序执行过程中得到正确维护。我不会做任何循环或数组搜索来减慢程序的速度。@Matthieu:同意。更正。为什么通过引用传递对象?我认为这在物体中并不重要。这是一个正确的答案。您需要一个支持依赖项注入的集合对象,这样您就可以向组中添加各种不同的怪物。接下来移除引用指针,并将
怪物
类指定为一个抽象类,由每种类型的怪物扩展。这个答案要求任何创建怪物的代码也可以访问
最新团队
查看我的答案。我真的不明白