with strip_tags special remove from eliminar code characters allow php reference binary-operators

php - special - string strip_tags



Jugando con referencias (2)

Es un comportamiento más o menos definido (pero a veces no documentado); principalmente porque $a no es una array sino un ArrayObject .

Veamos primero tu tercer fragmento de código:

$a = new ArrayObject(); $a[''ID''] = 42; $b = &$a[''ID'']; $c = $a; $c[''ID''] &= 0;

La última asignación se traduce en:

$tmp = &$c->offsetGet(''ID''); $tmp &= 0; // or: $tmp = $tmp & 0;

El punto de offsetGet() aquí solo se llama offsetGet() y devuelve una referencia a $c[''ID''] , como se indica en este comentario . Debido a que offsetSet() no se llama, el valor de $b cambia.

Por cierto, el incremento (++) y el operador de decremento (-) funcionan de manera similar, no se llama a offsetSet() .

Diferencias

Esto es diferente de tu primer ejemplo:

$a = new ArrayObject(); $a[''ID''] = 42; $b = &$a[''ID'']; $c = $a; $c[''ID''] = 37;

La última declaración tiene el siguiente equivalente:

$c->offsetSet(''ID'', 37);

Antes de asignar un nuevo valor a $c[''ID''] , el valor anterior es unset() ; esta es la razón por la que $b es la única variable que aún se mantiene en 42 .

Se puede ver una prueba de este comportamiento cuando usa objetos en lugar de números:

class MyLoggerObj { public function __destruct() { echo "Destruct of " . __CLASS__ . "/n"; } } $a = new ArrayObject(); $a[''ID''] = new MyLoggerObj(); $a[''ID''] = 37; echo $a[''ID'']."/n";

Output :

Destruct of MyLoggerObj 37

Como puede ver, el destructor se llama en MyLoggerObj ; eso es porque en este caso ya no hay ninguna variable que se aferre al valor.

Prima

Si intenta averiguar cuándo se offsetGet() y offsetSet() extendiendo ArrayObject se sentirá decepcionado al descubrir que no puede imitar de forma adecuada mixed &offsetGet($key); . De hecho, hacerlo cambia el comportamiento de ArrayObject de tal manera que es imposible probar el comportamiento de esta clase.

puedo ver porque

$a = new ArrayObject(); $a[''ID''] = 42; $b = &$a[''ID'']; $c = $a; $c[''ID''] = 37; echo $a[''ID'']."/n"; echo $b."/n"; echo $c[''ID'']."/n";

salidas 37, 42, 37

mientras

$a = new ArrayObject(); $a[''ID''] = 42; $b = &$a[''ID'']; $c = $a; $b = 37; echo $a[''ID'']."/n"; echo $b."/n"; echo $c[''ID'']."/n";

salidas 37, 37, 37

En ambos casos, $b es una referencia a $a[''ID''] mientras que $c es un puntero al mismo objeto que $a .

Cuando $b cambia $a[''ID''] y $c[''ID''] cambia porque la asignación de $b cambia el valor referenciado por $a[''ID''] .

Cuando $c[''ID''] cambia, se asigna un nuevo int a $a[''ID''] , $b ya no hace referencia a $a[''ID''] .

Pero esto me pica

$a = new ArrayObject(); $a[''ID''] = 42; $b = &$a[''ID'']; $c = $a; $c[''ID''] &= 0; $c[''ID''] |= 37; echo $a[''ID'']."/n"; echo $b."/n"; echo $c[''ID'']."/n";

(salidas 37, 37, 37)

¿Es este comportamiento definido? No vi nada de eso en la documentación ...


Tomemos este código como base: ( refcounting documentación )

$a = new ArrayObject(); $a[''ID''] = 42; $b = &$a[''ID'']; $c = $a; xdebug_debug_zval(''a''); xdebug_debug_zval(''b''); xdebug_debug_zval(''c'');

Esto da:

a: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=2, is_ref=1),int 42 b: (refcount=2, is_ref=1),int 42 c: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=2, is_ref=1),int 42

Como dice: $a es un objeto, $b es una referencia de $a[''ID''] ( $a[''ID''] y $b : refcount=2, is_ref=1 ) y $ c es una copia como referencia (desde PHP5) , entonces $ c es una referencia de $ a (ahora es el mismo objeto: refcount=2, is_ref=0 )

Si lo hacemos: $c[''ID''] = 37;

Obtenemos:

a: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=1, is_ref=0),int 37 b: (refcount=1, is_ref=0),int 42 c: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=1, is_ref=0),int 37

$c[''ID''] se le asigna un nuevo int así que =>

$b vuelve independiente ( refcount=1 and is_ref=0 ), así como $a[''ID''] y $c[''ID'']

PERO como $c y $a son dependientes, $a[''ID''] y $c[''ID''] toman el mismo valor 37.

Ahora, tomemos el código base y lo hacemos: $c[''ID''] &= 0;

ACTUALIZACIÓN : Inesperadamente, obtenemos:

a: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=2, is_ref=1),int 0 b: (refcount=2, is_ref=1),int 0 c: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=2, is_ref=1),int 0

en lugar de: (si: $c[''ID''] = $c[''ID''] & 0; )

a: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=1, is_ref=0),int 0 b: (refcount=1, is_ref=0),int 42 c: (refcount=2, is_ref=0), object(ArrayObject)[1] public ''ID'' => (refcount=1, is_ref=0),int 0

ArrayObject implementa ArrayAccess para:

Como se dice en el comentario y documentado aquí :

Una modificación directa es una que reemplaza completamente el valor de la dimensión de la matriz, como en $ obj [6] = 7. Una modificación indirecta, por otro lado, solo cambia parte de la dimensión, o intenta asignar la dimensión por referencia a otra variable, como en $ obj [6] [7] = 7 o $ var = & $ obj [6]. Los incrementos con ++ y los decrementos con - también se implementan de una manera que requiere una modificación indirecta.

Una posible respuesta:

"Operador combinado (+ =, - =, & =, | =) se podría trabajar de la misma manera (modificación indirecta)":

refcount y is_ref no se ven afectados, por lo que (en nuestro caso) se modifican los valores de todas las variables relacionadas. ( $c[''ID''] => $a[''ID''] => $b)