2009-01-24 41 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

相關問題