texto - PHP-Modificación indirecta de propiedad sobrecargada
string strip_tags (7)
Aunque llegué muy tarde a esta discusión, pensé que esto podría ser útil para alguien en el futuro.
Me enfrenté a una situación similar. La solución más fácil para aquellos a los que no les importa desarmar y restablecer la variable es hacerlo. Estoy bastante seguro de que la razón por la que esto no funciona está clara en las otras respuestas y en el manual de php.net. La solución más simple que funcionó para mí es
Suposición:
-
$object
es el objeto con__get
y__set
sobrecargado de la clase base, que no tengo libertad para modificar. -
shippingData
es la matriz por la que quiero modificar un campo, por ejemplo: - phone_number
// First store the array in a local variable.
$tempShippingData = $object->shippingData;
unset($object->shippingData);
$tempShippingData[''phone_number''] = ''888-666-0000'' // what ever the value you want to set
$object->shippingData = $tempShippingData; // this will again call the __set and set the array variable
unset($tempShippingData);
Nota: esta solución es una de las soluciones rápidas posibles para resolver el problema y obtener la variable copiada. Si la matriz es demasiado ruidosa, puede ser __get
forzar la reescritura del método __get
para devolver una copia de referencia de matrices grandes bastante costosa.
Sé que esta pregunta se ha formulado varias veces, pero ninguna de ellas tiene una respuesta real para una solución alternativa. Tal vez haya uno para mi caso específico.
Estoy construyendo una clase mapeador que usa el método mágico __get()
para cargar otros objetos de forma perezosa. Se ve algo como esto:
public function __get ( $index )
{
if ( isset ($this->vars[$index]) )
{
return $this->vars[$index];
}
// $index = ''role'';
$obj = $this->createNewObject ( $index );
return $obj;
}
En mi código, hago:
$user = createObject(''user'');
$user->role->rolename;
Esto funciona hasta ahora. El objeto User
no tiene una propiedad llamada ''role'', por lo que utiliza el __get()
magic __get()
para crear ese objeto y devuelve su propiedad del objeto ''role''.
Pero cuando intento modificar el ''nombre de rol'':
$user = createUser();
$user->role->rolename = ''Test'';
Entonces me da el siguiente error:
Aviso: la modificación indirecta de la propiedad sobrecargada no tiene efecto
No estoy seguro si esto todavía es un error en PHP o si es "comportamiento esperado", pero en cualquier caso no funciona de la manera que quiero. Esto es realmente un obstáculo para mí ... Porque ¿cómo demonios puedo cambiar las propiedades de los objetos cargados?
EDITAR:
El problema real solo parece ocurrir cuando devuelvo una matriz que contiene múltiples objetos.
He agregado una pieza de código de ejemplo que reproduce el problema:
Realmente deberías ejecutar esto en tu entorno PHP, realmente ver el ''error''. Pero hay algo realmente interesante pasando aquí.
Intento cambiar la propiedad de un objeto, lo que me da el aviso ''no puedo cambiar la propiedad sobrecargada''. Pero si hago eco de la propiedad después de eso, veo que realmente cambió el valor ... Realmente extraño ...
Estaba recibiendo este aviso por hacer esto:
$var = reset($myClass->my_magic_property);
Esto lo solucionó:
$tmp = $myClass->my_magic_property;
$var = reset($tmp);
Esto está ocurriendo debido a que PHP trata las propiedades sobrecargadas en el sentido de que no son modificables o pasadas por referencia.
Consulte el manual para obtener más información sobre la sobrecarga.
Para evitar este problema, puede usar una función __set
o crear un método createObject
.
A continuación se muestra un __get
y __set
que proporciona una solución alternativa a una situación similar a la suya, simplemente puede modificar el __set
para __set
a sus necesidades.
Tenga en cuenta que __get
nunca devuelve una variable. y más bien una vez que haya establecido una variable en su objeto, ya no estará sobrecargado.
/**
* Get a variable in the event.
*
* @param mixed $key Variable name.
*
* @return mixed|null
*/
public function __get($key)
{
throw new /LogicException(sprintf(
"Call to undefined event property %s",
$key
));
}
/**
* Set a variable in the event.
*
* @param string $key Name of variable
*
* @param mixed $value Value to variable
*
* @return boolean True
*/
public function __set($key, $value)
{
if (stripos($key, ''_'') === 0 && isset($this->$key)) {
throw new /LogicException(sprintf(
"%s is a read-only event property",
$key
));
}
$this->$key = $value;
return true;
}
Lo cual permitirá:
$object = new obj();
$object->a = array();
$object->a[] = "b";
$object->v = new obj();
$object->v->a = "b";
He tenido el mismo error, sin su código completo es difícil determinar exactamente cómo solucionarlo, pero es causado por no tener una función __set.
La forma en que lo he superado en el pasado es que he hecho cosas como esta:
$user = createUser();
$role = $user->role;
$role->rolename = ''Test'';
ahora si haces esto:
echo $user->role->rolename;
deberías ver ''Prueba''
Me encontré con el mismo problema que w00, pero no tuve la libertad de reescribir la funcionalidad básica del componente en el que ocurrió este problema (E_NOTICE). He podido solucionar el problema usando un ArrayObject en lugar del array de tipo básico () . Esto devolverá un objeto, que será devuelto por defecto por referencia.
Qué bueno que me diste algo para jugar con
correr
class Sample extends Creator {
}
$a = new Sample ();
$a->role->rolename = ''test'';
echo $a->role->rolename , PHP_EOL;
$a->role->rolename->am->love->php = ''w00'';
echo $a->role->rolename , PHP_EOL;
echo $a->role->rolename->am->love->php , PHP_EOL;
Salida
test
test
w00
Clase utilizada
abstract class Creator {
public function __get($name) {
if (! isset ( $this->{$name} )) {
$this->{$name} = new Value ( $name, null );
}
return $this->{$name};
}
public function __set($name, $value) {
$this->{$name} = new Value ( $name, $value );
}
}
class Value extends Creator {
private $name;
private $value;
function __construct($name, $value) {
$this->name = $name;
$this->value = $value;
}
function __toString()
{
return (string) $this->value ;
}
}
Editar: Nueva compatibilidad de matriz según lo solicitado
class Sample extends Creator {
}
$a = new Sample ();
$a->role = array (
"A",
"B",
"C"
);
$a->role[0]->nice = "OK" ;
print ($a->role[0]->nice . PHP_EOL);
$a->role[1]->nice->ok = array("foo","bar","die");
print ($a->role[1]->nice->ok[2] . PHP_EOL);
$a->role[2]->nice->raw = new stdClass();
$a->role[2]->nice->raw->name = "baba" ;
print ($a->role[2]->nice->raw->name. PHP_EOL);
Salida
Ok die baba
Clase modificada
abstract class Creator {
public function __get($name) {
if (! isset ( $this->{$name} )) {
$this->{$name} = new Value ( $name, null );
}
return $this->{$name};
}
public function __set($name, $value) {
if (is_array ( $value )) {
array_walk ( $value, function (&$item, $key) {
$item = new Value ( $key, $item );
} );
}
$this->{$name} = $value;
}
}
class Value {
private $name ;
function __construct($name, $value) {
$this->{$name} = $value;
$this->name = $value ;
}
public function __get($name) {
if (! isset ( $this->{$name} )) {
$this->{$name} = new Value ( $name, null );
}
if ($name == $this->name) {
return $this->value;
}
return $this->{$name};
}
public function __set($name, $value) {
if (is_array ( $value )) {
array_walk ( $value, function (&$item, $key) {
$item = new Value ( $key, $item );
} );
}
$this->{$name} = $value;
}
public function __toString() {
return (string) $this->name ;
}
}
Todo lo que necesita hacer es agregar "&" al frente de su función __get para pasarlo como referencia:
public function &__get ( $index )
Luchado con este por un tiempo.