2011-12-10 27 views
12

Estoy construyendo una matriz de objetos. Necesito que este conjunto contenga solo una instancia de un objeto dado, que tenga múltiples referencias al mismo objeto y arroje una excepción. Estoy utilizando el código siguiente para lograrlo:in_array en objetos con referencias circulares

public function addField ($name, iface\Node $field) 
{ 
    // Prevent the same field being added multiple times 
    if (!in_array ($field, $this -> fields)) 
    { 
     $this -> fields [$name] = $field; 
     $field -> setParent ($this); 
    } 
    else 
    { 
     throw new \InvalidArgumentException ('This field cannot be added to this group'); 
    } 
    return ($this); 
} 

Esto comenzó dando lugar a problemas cuando empecé a implementar los objetos que implementan la interfaz Node, ya que pueden incluir referencias circulares (que poseen una colección de sus nodos secundarios , con cada niño sosteniendo una referencia a su padre). Se trata de añadir un campo puede dar como resultado el siguiente error se genera:

PHP Fatal error: Nesting level too deep - recursive dependency?

sospecho que PHP está tratando de atravesar toda la gama de objetos, en lugar de comparar únicamente las referencias a objetos para ver si tienen el mismo valor y por lo tanto, apunta al mismo objeto.

Lo que necesito hacer en_array es simplemente comparar las referencias de objeto que almacena con la referencia de objeto del campo. Esto evitaría que intente atravesar todo el árbol de objetos y se encuentre con el problema de recursión.

¿Hay alguna forma de hacerlo?

+0

Intenta anular '__equals' en su objeto para implementar un método de comprobación de igualdad más adecuado para sus propósitos. –

Respuesta

16

Resulta que la respuesta es extraordinariamente simple. Parece que por defecto in_array hace una comparación no estricta (equivalente a una operación ==) cuando se prueba el pajar para la aguja. Esto significa que comprueba que todas las propiedades son iguales, lo que significa que comienza a atravesar el gráfico de objetos y eso puede generar problemas si tiene referencias circulares en ese gráfico.

La función in_array tiene un modo estricto, sin embargo, que por lo que yo sé equivale a una operación ===. Esto parece hacer que verifique las referencias para ver si apuntan al mismo objeto en lugar de comparar todas las propiedades.

Simplemente cambiando el código para:

if (!in_array ($field, $this -> fields, true)) 

hace que el método se comportan como quería que se comporte sin ella provocando el error recursividad.

Debo decir que estoy un poco sorprendido de que PHP no haga este modo por defecto. Por otro lado, creo que realmente no debería sorprenderme que la mecanografía débil de PHP me haya vuelto a causar problemas. :)

1

Solo usaría SplObjectStorage o spl_object_hash.

Y tienes razón, cuando php compara cosas atraviesa las estructuras recursivamente (matrices también).

+0

¿No hay una manera de comparar solo punteros? – mifki

+1

@mifki Puede escribir estricta === comparación. Comparará puntos por objetos. – NikiC

+0

Gracias por la respuesta, pero creo que he encontrado una solución. – GordonM

Cuestiones relacionadas