Получить все экземпляры класса в PHP

Я хотел бы получить все экземпляры объекта определенного класса.

Например:

class Foo { } $a = new Foo(); $b = new Foo(); $instances = get_instances_of_class('Foo'); 

$instances должен быть либо array($a, $b) либо array($b, $a) (порядок не имеет значения).

Плюсом является то, что функция вернет экземпляры с суперклассом запрошенного класса, хотя это необязательно.

Один из методов, о котором я могу думать, – это использовать статическую переменную-член класса, которая содержит массив экземпляров. В конструкторе класса и деструкторе я бы добавил или удалл $this из массива. Это довольно хлопотно и подвержено ошибкам, если я должен делать это на многих классах.

Если вы выведете все объекты из класса 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() нужно будет вызывать вручную для уничтожения указанного объекта. (Circular Reference Garbage Collection была добавлена ​​в PHP 5.3 и может содержать дополнительные возможности сбора мусора)

Вот возможное решение:

 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; } 

Я не уверен, может ли он перейти в бесконечную рекурсию с определенными объектами, поэтому будьте осторожны …

Мне нужно это, потому что я создаю систему событий и должен иметь возможность отправлять события ко всем объектам определенного класса (глобальное уведомление, если хотите, которое динамически связано).

Я хотел бы предложить отдельный объект, где вы регистрируете объекты с помощью ( Шаблон наблюдателя ). PHP имеет встроенную поддержку для этого через spl; См. SplObserver и SplSubject .

Насколько я знаю, среда выполнения PHP не раскрывает базовое пространство объектов, поэтому было бы невозможно запросить ее для экземпляров объекта.