2009-01-24 12 views
9

Me gustaría obtener todas las instancias de un objeto de cierta clase.Obtenga todas las instancias de una clase en PHP

Por ejemplo:

class Foo { 
} 

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

$instances = get_instances_of_class('Foo'); 

$instances debe ser o bien array($a, $b) o array($b, $a) (orden no importa).

Un más es si la función devolvería instancias que tienen una superclase de la clase solicitada, aunque esto no es necesario.

Un método que se me ocurre es utilizar una variable de miembro de clase estática que contiene una matriz de instancias. En el constructor y el destructor de la clase, agregaría o eliminaría $this de la matriz. Esto es bastante problemático y propenso a errores si tengo que hacerlo en muchas clases.

+2

¿Por qué siente que necesita esto? – troelskn

+2

@troelskn, lo necesito porque estoy creando un sistema de eventos y necesito poder enviar eventos a todos los objetos de una determinada clase (una notificación global, si se quiere, que está vinculada dinámicamente). – strager

Respuesta

14

Si derivar todos los objetos de una clase TrackableObject, esta clase podría ser configurado para manejar este tipo de cosas (sólo asegúrese de llamar parent::__construct() y parent::__destruct() cuando los sobrecarga en las subclases.

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

El principal problema con esto es que no hay ningún objeto sería recogido de forma automática por la recolección de basura (como todavía existe una referencia a él dentro de TrackableObject::$_instances), por lo __destruct() tendría que ser llamado para destruir manualmente dicho objeto. (La Recolección de Basura de Referencia Circular fue agregada en PHP 5.3 y puede presentar oportunidades adicionales de recolección de basura)

+1

Esto fue básicamente mi idea inicial. Trataré de implementarlo. – strager

+1

Pregunta: would not getInstances be static? – strager

+1

Sí, sería, era bastante tarde cuando escribí esto, pero está en lo cierto, señor. –

2

Hasta donde yo sé, el tiempo de ejecución de PHP no expone el espacio de objetos subyacente, por lo que no sería posible consultarlo para las instancias de un objeto.

+2

¿Tiene alguna fuente para confirmar esto? – strager

5

Aquí hay una solución posible:

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

Editar: Se ha actualizado el código para comprobar si el $class es una superclase.

Editar 2: Hecho una más desordenado ligeramente la función recursiva que comprueba las variables de cada objeto en lugar de sólo los objetos de nivel superior:

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

no estoy seguro de si se puede entrar en la recursividad infinita con cierta objetos, así que ten cuidado ...

+0

Esto no funciona tan bien como me gustaría. La mayoría de mis instancias son miembros de algunas otras clases. – strager

+0

He actualizado mi respuesta con una función recursiva que busca instancias en todos los miembros de todos los objetos (y todos los miembros de esos miembros, ...). –

+0

Hay otro problema: variables temporales. No creo que puedas cubrir todos los rincones con $ GLOBALS, lo que probablemente introduciría errores inesperados. Estoy seguro de que su método sería útil para otra persona, sin embargo, con necesidades menos específicas. – strager

2

Necesito esto porque estoy creando un sistema de eventos y necesito poder enviar eventos a todos los objetos de una cierta clase (una notificación global, si se quiere, que está vinculada dinámicamente).

Sugeriría tener un objeto separado donde registrar objetos con (Un observer pattern). PHP tiene soporte integrado para esto, a través de spl; Ver: SplObserver y SplSubject.

+0

Me gustaría un sistema más parecido a las señales y ranuras de Qt. El comportamiento que quiero en particular es como tal: tengo clases ChatRoom, que activan un mensaje de eventoEnviado cuando alguien envía un mensaje. Me gustaría que una clase MessageFilter filtre CUALQUIER mensaje enviado a través de CUALQUIER ChatRoom. – strager

+1

¿Quieres un observador global? Puede crear una variable global, o puede pasar la misma instancia a todas las ChatRooms – troelskn

Cuestiones relacionadas