2009-01-24 45 views
9

我想获得某个类的对象的所有实例。在PHP中获取一个类的所有实例

例如:

class Foo { 
} 

$a = new Foo(); 
$b = new Foo(); 

$instances = get_instances_of_class('Foo'); 

$instances应该是array($a, $b)array($b, $a)(顺序无关紧要)。

A plus是如果该函数将返回具有所请求类的超类的实例,但这不是必需的。

我能想到的一种方法是使用一个静态类成员变量,它包含一个实例数组。在该类的构造函数和析构函数中,我将从数组中添加或删除$this。如果我必须在很多课上做,这很麻烦,容易出错。

+2

你为什么觉得你需要这个? – troelskn 2009-01-24 12:25:42

+2

@troelskn,我需要这个,因为我正在制作一个事件系统,并且需要能够将事件发送到某个类的所有对象(全局通知,如果您愿意的话,它是动态绑定的)。 – strager 2009-01-24 19:39:58

回答

14

如果你得到所有对象从TrackableObject类,这个类可以设立来处理这样的事情(只要确保你打电话parent::__construct()parent::__destruct()超载那些在子类时。

class TrackableObject 
{ 
    protected static $_instances = array(); 

    public function __construct() 
    { 
     self::$_instances[] = $this; 
    } 

    public function __destruct() 
    { 
     unset(self::$_instances[array_search($this, self::$_instances, true)]); 
    } 

    /** 
    * @param $includeSubclasses Optionally include subclasses in returned set 
    * @returns array array of objects 
    */ 
    public static function getInstances($includeSubclasses = false) 
    { 
     $return = array(); 
     foreach(self::$_instances as $instance) { 
      if ($instance instanceof get_class($this)) { 
       if ($includeSubclasses || (get_class($instance) === get_class($this)) { 
        $return[] = $instance; 
       } 
      } 
     } 
     return $return; 
    } 
} 

与此主要问题是,没有对象会被垃圾回收自动拾取(作为对它的引用中TrackableObject::$_instances依然存在),因此__destruct()将需要手动调用来摧毁上述目标。 (循环引用垃圾收集是PHP 5.3中添加和可能存在额外的垃圾收集机会)

2

据我所知,PHP运行库不公开底层对象空间,所以不可能为对象的实例查询它。

+2

你有什么消息来证实这一点吗? – strager 2009-01-24 05:36:25

5

这里是一个可能的解决方案:

function get_instances_of_class($class) { 
    $instances = array(); 

    foreach ($GLOBALS as $value) { 
     if (is_a($value, $class) || is_subclass_of($value, $class)) { 
      array_push($instances, $value); 
     } 
    } 

    return $instances; 
} 

编辑:更新的代码检查$class是一个超类。

编辑2:由轻微梅西耶,检查每个对象的变量,而不是只在顶级对象递归函数:

function get_instances_of_class($class, $vars=null) { 
    if ($vars == null) { 
     $vars = $GLOBALS; 
    } 

    $instances = array(); 

    foreach ($vars as $value) { 
     if (is_a($value, $class)) { 
      array_push($instances, $value); 
     } 

     $object_vars = get_object_vars($value); 
     if ($object_vars) { 
      $instances = array_merge($instances, get_instances_of_class($class, $object_vars)); 
     } 
    } 

    return $instances; 
} 

我不知道这是否可以进入某些无限递归对象,所以要小心......

+0

这并不如我所愿。我的大部分实例都是其他类的成员。 – strager 2009-01-24 06:26:44

+0

我用一个递归函数更新了我的答案,该函数在所有对象(以及这些成员的所有成员...)的所有成员中查找实例。 – 2009-01-24 06:55:19

2

我需要这个,因为我想提出一个事件系统,需要能够发送事件到某一类的所有对象(一个全局通知,如果你愿意的话,它是动态绑定的)。

我会建议有一个单独的对象,你注册对象(安)observer pattern)。 PHP通过spl已经内置了对此的支持;参见:SplObserverSplSubject

相关问题