我想获得某个类的对象的所有实例.
例如:
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()
需要手动调用以销毁所述对象.(循环引用垃圾收集在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; }
我不确定它是否可以与某些对象进行无限递归,所以要小心......