在PHP中获取类的所有实例

时间:2009-01-24 05:31:01

标签: php class dynamic

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

例如:

class Foo {
}

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

$instances = get_instances_of_class('Foo');

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

一个加号是函数是否会返回具有所请求类的超类的实例,尽管这不是必需的。

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

4 个答案:

答案 0 :(得分:15)

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

答案 1 :(得分: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;
}

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

答案 2 :(得分:2)

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

答案 3 :(得分:2)

  

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

我建议使用一个单独的对象来注册对象(An observer pattern)。 PHP通过spl内置了对此的支持;请参阅:SplObserverSplSubject