Dynamic Properties in PHP and StdClass
Written by Kris on November 27th, 2008Languages like JavaScript and Python allow object instances to have dynamic properties. As it turns out, PHP does too. Looking at the official PHP documentation on objects and classes you might be lead to believe dynamic instance properties require custom __get and __set magic methods. They don’t.
Simple, Built-in Dynamic Properties
Check out the following code listing:
class DynamicProperties { }
$object = new DynamicProperties;
print isset($object->foo) ? 't' : 'f'; // f
// Set Dynamic Properties foo and fooz
$object->foo = 'bar';
$object->fooz = 'baz';
// Isset and Unset work
isset($object->foo); // true
unset($object->foo);
// Iterate through Properties and Values
foreach($object as $property => $value) {
print($property . ' = ' . $value . '<br />');
}
// Prints:
// fooz = baz
Using the built-in dynamic instance properties is an order of magnitude faster (30x, by my profiling) than using magic __get and __set methods. Built in dynamic property accesses happen without invoking a method call back to PHP script.
So when does it make sense to use __get and __set? If you need more complex behavior, like calculated properties, you must use __get and __set. Also, as an astute comment points out, if you would prefer not to have dynamic properties on a class you can throw errors from __get and __set.
StdClass: Anonymous Objects
Sometimes all that is necessary is a property bag to throw key value pairs into. One way is to use array, but this requires quoting all keys. Another way is to use dynamic properties on an instance of StdClass. StdClass is a sparsely documented class in PHP which has no predefined members.
$object = new StdClass; $object->foo = 'bar'; json_encode($object);
Next I’ll touch on the SPL’s Countable and ArrayAccess as a means of being able to accomplish the following in PHP:
class MyClass implements Countable, ArrayAccess { ... }
$myObject = new MyClass();
// Using array access notation
$myObject[0] = 'hello';
$myObject[1] = 'world';
$myObject['foo'] = 'bar';
Thanks to the folks pointing out that you don’t need to extend from StdClass in order to have dynamic properties!
Follow on Twitter
27
PM
Dynamic instance properties can be set on any class irregardless of whether or not they extend from stdClass. Declaring properties is entirely optional in PHP and always has been.
Try your BestDynamicProperties example without extending from stdClass and you’ll see that you get exactly the same result. Now try adding properties to any other PHP class and you’ll notice that works as well. stdClass is just an empty class, it has no special abilities.
If you don’t want dynamic properties on your classes (I usually don’t to cut down on typos going unnoticed), you can define the __set() magic method to throw an exception.
27
PM
this is great, I didn’t know about stdClass. Where did you find the docs? the only mention I can find on php.net is “The name stdClass is used internally by Zend and is reserved. You cannot have a class named stdClass in PHP.”
27
PM
Instead of :
class DynamicProperties extends StdClass { }
$object = new DynamicProperties;
You can do just:
class foo {};
$object = new foo();
and the rest of your code still works. No need to extend stdClass at all.
27
PM
@Duke, @Wayne – Thanks for the heads up. I’ve corrected the post. Amazing the range of things PHP doesn’t make obvious in the official documentation. I’ve been using __get and __set in simple dynamic properties cases for years.
@Scott – StdClass is neat and nebulous. There really isn’t much about it on the net. It has been claimed to be the base class for all other classes in PHP but the following code bit returns false:
echo $b instanceof stdclass ? 'yes' : 'no'; // prints 'no'
26
PM
class foo {};
$object = new foo();
try above
24
PM
had too google far & wide to find your piece. any idea why this isn’t documented in php.net? if it’s a feature, it should be documented, but if not, it’s a bug and ought to be fixed. it certainly gives the lie to the often-repeated advice to look it up in the php documentation.
9
AM
Sometimes you need declaring objects on the fly just to hold abstract members, say for packing. To use $object = new foo(); you should have declared class foo{}, while you can just object=new stdclass;
9
PM
If you want to set multiple properties on a single line, you can do:
$object = (object)array(‘key’ => ‘value’, ‘key2′ => ‘value2′);
The object created will be an stdClass instance.