我想获得某个类的对象的所有实例。
例如:
class Foo {
}
$a = new Foo();
$b = new Foo();
$instances = get_instances_of_class('Foo');
$instances
应为array($a, $b)
或array($b, $a)
(顺序无关紧要)。
一个加号是函数是否会返回具有所请求类的超类的实例,尽管这不是必需的。
我能想到的一个方法是使用一个包含实例数组的静态类成员变量。在类的构造函数和析构函数中,我将从数组中添加或删除$this
。如果我必须在很多课程中这样做,这是相当麻烦和容易出错的。
答案 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内置了对此的支持;请参阅:SplObserver和SplSubject。