10

特定のクラスのオブジェクトのすべてのインスタンスを取得したいと思います。

例えば:

class Foo {
}

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

$instances = get_instances_of_class('Foo');

$instancesまたはのいずれかである必要がありますarray($a, $b)array($b, $a)順序は関係ありません)。

プラスは、関数が要求されたクラスのスーパークラスを持つインスタンスを返す場合ですが、これは必須ではありません。

私が考えることができる1つの方法は、インスタンスの配列を保持する静的クラスメンバー変数を使用することです。クラスのコンストラクタとデストラクタで$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を介したこれに対する組み込みのサポートがあります。SplObserverおよびSplSubjectを参照してください。

于 2009-01-27T11:44:28.717 に答える