Получить все экземпляры класса в PHP - PullRequest
10 голосов
/ 24 января 2009

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

Например:

class Foo {
}

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

$instances = get_instances_of_class('Foo');

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

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

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

Ответы [ 4 ]

15 голосов
/ 24 января 2009

Если вы извлекаете все свои объекты из класса 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 и может представлять дополнительные возможности сбора мусора)

6 голосов
/ 24 января 2009

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

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

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

2 голосов
/ 27 января 2009

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

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

2 голосов
/ 24 января 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...