10

我想获取某个类的对象的所有实例。

例如:

class Foo {
}

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

$instances = get_instances_of_class('Foo');

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

一个优点是该函数将返回具有所请求类的超类的实例,尽管这不是必需的。

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

4

4 回答 4

17

如果您从 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 中添加的,可能会提供额外的垃圾收集机会)

于 2009-01-24T06:14:02.497 回答
6

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

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

我不确定它是否可以与某些对象进行无限递归,所以要小心......

于 2009-01-24T05:59:15.960 回答
2

据我所知,PHP 运行时不会公开底层对象空间,因此无法查询它以获取对象的实例。

于 2009-01-24T05:33:40.973 回答
2

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

我建议有一个单独的对象,您可以在其中注册对象(观察者模式)。PHP 通过 spl 内置了对此的支持;请参阅:SplObserverSplSubject

于 2009-01-27T11:44:28.717 回答