Cómo agregar una propiedad al objeto en PHP> = 5.3 modo estricto sin generar error

81

Esto tiene que ser simple, pero parece que no puedo encontrar una respuesta ...

Tengo un objeto stdClass genérico $foosin propiedades. Quiero agregarle una nueva propiedad $barque aún no está definida. Si hago esto:

$foo = new StdClass();
$foo->bar = '1234';

PHP en modo estricto se queja.

¿Cuál es la forma correcta (fuera de la declaración de clase) para agregar una propiedad a un objeto ya instanciado?

NOTA: Quiero que la solución funcione con el objeto PHP genérico de tipo stdClass.

Un poco de historia sobre este tema. Estoy decodificando una cadena json que es una matriz de objetos json. json_decode()genera una matriz de objeto StdClass. Necesito manipular estos objetos y agregar una propiedad a cada uno.

Rayo
fuente
Intente pasar TRUEcomo segundo parámetro a json_decode. Le dará una matriz asociativa en lugar de una matriz de objetos.
Rocket Hazmat
1
PHP en modo estricto no se queja de eso. 3v4l.org/kn0hi
hakre
3
No sé por qué se ha cerrado esto, ya que es una pregunta perfectamente válida. Tengo una pregunta exactamente similar en este momento.
Steven

Respuestas:

130

Si es absolutamente necesario agregar la propiedad al objeto, creo que podría convertirlo en una matriz, agregar su propiedad (como una nueva clave de matriz) y luego devolverla como un objeto. La única vez que te encuentras con stdClassobjetos (creo) es cuando lanzas una matriz como un objeto o cuando creas un nuevo stdClassobjeto desde cero (y, por supuesto, cuando tienes json_decode()algo, ¡tonto por olvidar!)

En vez de:

$foo = new StdClass();
$foo->bar = '1234';

Harías:

$foo = array('bar' => '1234');
$foo = (object)$foo;

O si ya tenía un objeto stdClass existente:

$foo = (array)$foo;
$foo['bar'] = '1234';
$foo = (object)$foo;

También como 1 delineador:

$foo = (object) array_merge( (array)$foo, array( 'bar' => '1234' ) );
Crontab
fuente
1
Un lugar donde se encuentra StdClass es cuando decodifica json, que es bastante común.
Ray
1
@Ray Estoy negando con la cabeza con tristeza porque no pensé en mencionar eso. =)
Crontab
3
Tu solución funciona, pero me duele el corazón de OO :) Esperaba algún tipo de reflejo llamativo kung foo o algo ... Voy a mantener la pregunta abierta un poco más y espero algo de magia PHP poco conocida.
Ray
1
@Ray jejeje ... Desearía tener algo más elegante para ti. Por cierto, al establecer explícitamente error_reporting(E_STRICT);en PHP 5.3.15-1~dotdeb.0 with Suhosin-Patch, no obtengo ningún error o aviso cuando intento establecer una propiedad inexistente en un objeto stdClass. ¿Qué versión de PHP estás usando?
Crontab
Ja, casi tres años después y recibí un voto negativo sin explicación por alguna razón. Gracias.
Crontab
111

Hazlo asi:

$foo = new stdClass();
$foo->{"bar"} = '1234';

ahora intenta:

echo $foo->bar; // should display 1234
jmnerd
fuente
2
Funciona como encanto. Esta debería ser la solución aceptada.
Tarrakis
¿Cómo se agrega una propiedad a un campo en un objeto usando esta sintaxis?
Big Money
Error 'Intento de asignar propiedad de no objeto' en Laravel
Rejaul
incluso la cadena "bar" puede estar en una variable: $ foo -> {$ any_variable} = '1234';
Salar
Esta debería ser definitivamente la respuesta aceptada, ya que mantiene intacta la referencia del objeto (que en mi caso fue crucial).
Johan Fredrik Varen
11

Si desea editar el JSON decodificado, intente obtenerlo como una matriz asociativa en lugar de una matriz de objetos.

$data = json_decode($json, TRUE);
Cohete Hazmat
fuente
2

Yo siempre uso de esta manera:

$foo = (object)null; //create an empty object
$foo->bar = "12345";

echo $foo->bar; //12345
Ragnar
fuente
1

debe utilizar los métodos mágicos __Set y __get. Ejemplo simple:

class Foo
{
    //This array stores your properties
private $content = array();

public function __set($key, $value)
{
            //Perform data validation here before inserting data
    $this->content[$key] = $value;
    return $this;
}

public function __get($value)
{       //You might want to check that the data exists here
    return $this->$content[$value];
}

}

Por supuesto, no use este ejemplo como este: no hay seguridad en absoluto :)

EDITAR: visto sus comentarios, aquí podría haber una alternativa basada en la reflexión y un decorador:

 class Foo
 {
private $content = array();
private $stdInstance;

public function __construct($stdInstance)
{
    $this->stdInstance = $stdInstance;
}

public function __set($key, $value)
{
    //Reflection for the stdClass object
    $ref = new ReflectionClass($this->stdInstance);
    //Fetch the props of the object

    $props = $ref->getProperties();

    if (in_array($key, $props)) {
        $this->stdInstance->$key = $value;
    } else {
        $this->content[$key] = $value;
    }
    return $this;
}

public function __get($value)
{
    //Search first your array as it is faster than using reflection
    if (array_key_exists($value, $this->content))
    {
        return $this->content[$value];
    } else {
        $ref = new ReflectionClass($this->stdInstance);

        //Fetch the props of the object
        $props = $ref->getProperties();

        if (in_array($value, $props)) {

        return $this->stdInstance->$value;
    } else {
        throw new \Exception('No prop in here...');
    }
}
 }
}

PD: No probé mi código, solo la idea general ...

Benjamin Dubois
fuente
3
Benjamin, quiero usar la clase de objeto genérico de PHP: StdClass. No puedo modificar esta clase.
Ray
Ray, actualicé mi respuesta con una solución correspondiente a su necesidad, pero es pesada: - /
Benjamin Dubois
1

No sé si es la versión más nueva de php, pero funciona. Estoy usando php 5.6

    <?php
    class Person
    {
       public $name;

       public function save()
       {
          print_r($this);
       }
    }

   $p = new Person;
   $p->name = "Ganga";
   $p->age = 23;

   $p->save();

Este es el resultado. El método de guardar realmente obtiene la nueva propiedad

    Person Object
    (
       [name] => Ganga
       [age] => 23
    )
Ganga
fuente
Ejecuté varias pruebas para el código en las versiones de php y el resultado muestra que solo funciona para php 5 y superior. cualquier versión por debajo de php5 arroja un error.
Big Tree
-6

Sí, es posible agregar propiedades dinámicamente a un objeto PHP.

Esto es útil cuando se recibe un objeto parcial de javascript.

Lado JAVASCRIPT:

var myObject = { name = "myName" };
$.ajax({ type: "POST", url: "index.php",
    data: myObject, dataType: "json",
    contentType: "application/json;charset=utf-8"
}).success(function(datareceived){
    if(datareceived.id >= 0 ) { /* the id property has dynamically added on server side via PHP */ }
});

Lado PHP:

$requestString = file_get_contents('php://input');
$myObject = json_decode($requestString); // same object as was sent in the ajax call
$myObject->id = 30; // This will dynamicaly add the id property to the myObject object

O SÓLO ENVIAR UNA PROPIEDAD DUMMY desde JavaScript que completará en PHP.

Adrian Cumpanasu
fuente
Creo que enviar una propiedad ficticia desde JS y completar en el lado de PHP es la solución más fácil e inteligente. ¡Gracias!
Adrian P.
8
o_O O_o o_O O_o
theflowersoftime