103

This has to be simple, but I can't seem to find an answer....

I have a generic stdClass object $foo with no properties. I want to add a new property $bar to it that's not already defined. If I do this:

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

PHP in strict mode complains.

What is the proper way (outside of the class declaration) to add a property to an already instantiated object?

NOTE: I want the solution to work with the generic PHP object of type stdClass.

A little background on this issue. I'm decoding a json string which is an array of json objects. json_decode() generates an array of StdClass object. I need to manipulate these objects and add a property to each one.

4
  • Try passing TRUE as a 2nd parameter to json_decode. It'll give you an associative array instead of an array of objects. Commented Jul 23, 2012 at 18:54
  • 2
    PHP in strict mode does not complain about that. 3v4l.org/kn0hi Commented Apr 18, 2013 at 17:09
  • 4
    I don't know why this has been closed since this is a perfectly valid question. I have an exact similar question right now. Commented May 30, 2014 at 18:14
  • Can any of the people who've upvoted this question and its answers explain what exactly the supposed error here is? Even the recently passed RFC which will make dynamic properties an error in PHP 9.0 explicitly allows them on stdClass, because that's kind of the point of it. I can only think there is actually some "code style" tool which people are blindly "tricking" with the answers below. Commented Jan 18, 2022 at 15:27

6 Answers 6

163

If you absolutely have to add the property to the object, I believe you could cast it as an array, add your property (as a new array key), then cast it back as an object. The only time you run into stdClass objects (I believe) is when you cast an array as an object or when you create a new stdClass object from scratch (and of course when you json_decode() something - silly me for forgetting!).

Instead of:

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

You'd do:

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

Or if you already had an existing stdClass object:

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

Also as a 1 liner:

$foo = (object) array_merge( (array)$foo, array( 'bar' => '1234' ) );
Sign up to request clarification or add additional context in comments.

2 Comments

Your solution works, but it hurts my OO heart :) Was hoping for some type of flashy reflection kung foo or something... Going to keep the question open a bit longer and hope for some little known PHP magic.
@Ray hehehe... I wish I had something more elegant for you. Incidentally, explicitly setting error_reporting(E_STRICT); on PHP 5.3.15-1~dotdeb.0 with Suhosin-Patch, I don't get any errors or notices when attempting to set a non-existent property on a stdClass object. What version of PHP are you using?
163

Do it like this:

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

now try:

echo $foo->bar; // should display 1234

6 Comments

How do you add a property to a field on an object using this syntax?
'Attempt to assign property of non-object' Error in Laravel
even the "bar" string can be in a variable: $foo->{$any_variable} = '1234';
I think this is the best answer, as it keeps the object reference intact (which in my case was crucial).
This makes no sense. $foo->{"bar"} is just a different syntax for $foo->bar, which I'm pretty sure will be handled exactly the same by the compiler before the code is ever run, and any decent static analysis tool should treat it the same way too. Can anyone explain what error this supposedly avoids?
|
11

If you want to edit the decoded JSON, try getting it as an associative array instead of an array of objects.

$data = json_decode($json, TRUE);

Comments

9

This is another way:

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

echo $foo->bar; //12345

Comments

1

you should use magic methods __Set and __get. Simple example:

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

}

Of course, don't use this example as this : no security at all :)

EDIT : seen your comments, here could be an alternative based on reflection and a decorator :

 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...');
    }
}
 }
}

PS : I didn't test my code, just the general idea...

2 Comments

Benjamin, I want to use PHP's generic object class: StdClass. I cannot modify this class.
Ray, I updated my answer with a solution corresponding to your need, but it's heavy :-/
1

I don't know whether its the newer version of php, but this works. I'm using 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();

This is the result. The save method actually gets the new property

    Person Object
    (
       [name] => Ganga
       [age] => 23
    )

1 Comment

I ran several test for the code across php versions and result shows it only works for php 5 and above. any version below php5 throws an error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.