JavaScript-style object literals in PHP
The object literal notation in JavaScript looks like:
var fido = {name: "Fido", barks: true};
or
var fido = {}; fido.name = "Fido"; fido.barks = true;
From assoc arrays to objects
In PHP you would call that an associative array.
$fido = array( 'name' => "Fido", 'barks' => true );
And you can easily make it an object too:
$fido = (object)$fido; echo gettype($fido); // "object"
Or if you want to start with a blank object and add stuff to it:
$fido = (object)array();
or
$fido = new StdClass();
and then
$fido->name = "Fido"; $fido->barks = true;
A little explanation maybe: objects in JavaScript are hashes, maps, whatever you decide to call them. Objects in PHP were an afterthought in the language and (at least initially) were not much more than "fancy arrays". Fancy associative arrays (hashes, maps, whatever you call them).
Objects in PHP need a class, but the new stdClass() lets you start quickly without the class {...} jazz. Same for casting an array (upgrading it in its fanciness) to an object with (object)array().
So far - so good. What about methods?
Methods anyone?
JavaScript doesn't care about properties versus methods. It's all members of an object (like elements of an assoc array). Only if a member happens to be a function, it's invokable.
fido.say = function () { if (this.barks) { return "Woof!"; } }; fido.say(); // "Woof!"
Turns out, since PHP 5.3 there are closures in PHP too. So you can do:
$fido->say = function() { if ($this->barks) { return "Woof"; } };
The difference is that $fido->say() won't work. Two reasons for that:
sayis not a method. It's a property. For PHP it matters. You can however assign the propertysayto a new variable$callme. This variable is now a closure object. As such you can invoke it:$callme = $fido->say; echo $callme();
Note the
$in$callme().- the above will also fail because
$thisis an weird context and doesn't point to the object$fido. But you can use$selfand point it to the global object$fido.
So that's a little .... unpretty, but it works:
$fido = (object)array(); $fido->name = "Fido"; $fido->barks = true; $fido->say = function() { $self =& $GLOBALS['fido']; if ($self->barks) { return "Woof"; } }; $callme = $fido->say; echo $callme(); // "Woff!"
And a sprinkle of magic
We can make this prettier with the help of a little PHP magic. PHP has some magic methods going on and one of these is the __call() method. If you implement it in a class, then it will be invoked whenever someone tries to call a method that doesn't exist.
In our case $fido->say is not a method. So __call can intercept $fido->say() calls and invoke the $fido->say property as a closure object. Closures are callable and call_user_func() and call_user_func_array() work fine with them. So all in all we should make this work:
$fido = new JSObject(); $fido->name = "Fido"; $fido->barks = true; $fido->say = function($self) { if ($self->barks) { return "Woof"; } }; echo $fido->say();
As you can see, very JavaScript-esque. Except that $this is $self and will always be the first argument passed to every method. The secret sauce to make this happen is the JSObject() class.
class JSObject { function __call($name, $args) { if (is_callable($this->$name)) { array_unshift($args, $this); return call_user_func_array($this->$name, $args); } } }
Nice and easy. Namely:
__calltakes the name of the missing method and any arguments.- It checks whether there's a callable property with the same name (a closure object property).
- It adds
$thisto the arguments list and calls the closure.
Yupee! Now you can haz moar class-less JS-like PHP objects
(Note that $this->$name is not a typo and should not be $this->name because it's a dynamic property name.)
And one more thing
If we add a constructor to JSObject, it can accept any properties at creation time. So you can be even closer to JavaScript and allow both creating an "empty" object and adding to it later, or creating an object and adding properties simultaneously.
The slightly modified JSObject:
class JSObject { function __construct($members = array()) { foreach ($members as $name => $value) { $this->$name = $value; } } function __call($name, $args) { if (is_callable($this->$name)) { array_unshift($args, $this); return call_user_func_array($this->$name, $args); } } }
And example use:
$fido = new JSObject(array( 'name' => "Fido", 'barks'=> true, 'say' => function($self) { if ($self->barks) { return "Woof"; } } )); echo $fido->say(); // "Woff"
This is pretty close to what you can have in JavaScript (adding $ and ' even though we can do without them), only changing a few things like -> to . and => to :
$fido = { 'name' : "Fido", 'barks': true, 'say' : function() { if (this.barks) { return "Woof"; } } }; $fido.say(); // Woof
JS and PHP look like twins now don't they.
JS for PHP devs at confoo.ca
This was extracted from a talk I gave at the confoo.ca conference a week or so ago. Below are the slides:
This entry was posted on Sunday, March 20th, 2011 and is filed under JavaScript, php. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
Get notification for future posts: follow me on Twitter or subscribe to my RSS feed

March 20th, 2011 at 3:24 am
[...] See thе first post: JavaScript-stylishness object literals іn PHP / Stoyan's phpied.com [...]
March 20th, 2011 at 4:40 am
For older PHP versions (<5.3) I've used the static classes pattern
class Fido{
static $name=”Fido”;
static $barks=true;
static function say(){
if(self::$barks){
return “Woof”;
}
}
}
echo Fido::say();
Ain’t so pretty, doesn’t have closures and is not easily mutable but it works
March 20th, 2011 at 7:53 am
This is really interesting, but it seems that I missed the point. Where’s the benefit of forcing PHP to have similar syntax as JS ?
March 20th, 2011 at 8:11 am
PHP is a truly hideous language. Why not start developing with Node for server-side work and you can forget you ever learnt that horrible mess that is PHP.
March 20th, 2011 at 11:00 am
I had some fun with the same concepts a couple of months ago.
You can push the similes with JavaScript even further.
Here, for instance, I experimented with prototypal inheritance:
https://gist.github.com/803151#file_prototypal_inheritance.php
Here is a version of the famous JavaScript module pattern:
https://gist.github.com/803151#file_module_pattern.php
I then tried to see if I could apply some of the pattern common to functional programming in PHP.
I managed to get an example of memoization (https://gist.github.com/803151#file_memoization.php) and curry (https://gist.github.com/803151#file_curry.php)
It’s all fun, but I honestly haven’t found a single serious usage for all of this stuff! ; )
March 20th, 2011 at 3:11 pm
Another thing to note is that you can easily access the values of specific keys as long as they contain only alphanumerical characters (and don’t start with a number). For example, in JavaScript you can just use
obj.footo access the corresponding value of thefookey in the object literal. In PHP, you would do$obj->foo.It gets more complicated when the key contains stuff like hyphens, spaces, or other non-alphanumerical characters. For example,
obj.foo bar(JS) obviously won’t work, and the same goes for$obj->foo barin PHP.It’s still possible to access the values for these keys though, and here’s how:
JavaScript:
var obj = { 'foo bar': 42 }; obj['foo bar']; // 42PHP:
<?php $obj = (object) array( 'foo bar' => 42 ); $obj->{'foo bar'}; // 42 ?>March 20th, 2011 at 3:45 pm
I wonder if we could use call_user_func_array(array($this, $this->name), $args) instead. (Not tested)
March 20th, 2011 at 8:55 pm
[...] JavaScript-style object literals in PHP / Stoyan's phpied.com [...]
March 21st, 2011 at 9:03 am
Your function example is not quite accurate.
function junction(a, b) {
b = b || 2;
return a * b;
}
function junction($a, $b = 2) {
return $a * $b;
}
The two calls are not identical when b is a falsy value, like 0. JavaScript will return a * 2. PHP will return $a * 0.
March 21st, 2011 at 9:04 am
Nevermind me, I missed the slide directly after it!
March 21st, 2011 at 9:32 am
[...] JavaScript-style object literals in PHP / Stoyan's phpied.com [...]
March 21st, 2011 at 10:09 am
Thank you for sharing this Stoyan.
I’ve experimented with making my PHP a bit more javascript-like and this will be a very useful snippet of code to play with.
@Ryan, sometimes Node, or other server-side-javascript solutions, cannot be used. I’ve delved into legacy php code many times and it helps to have simple solutions like this to make the PHP code more familiar/similar to the front-end javascript.
March 21st, 2011 at 7:52 pm
[...] JavaScript-style object literals in PHP / Stoyan's phpied.com [...]
March 27th, 2011 at 5:56 am
I find the use-this-language-instead-of-that argument silly. This post, for me at least, is about how programming conventions or historic limitations lead you to believe that a concept from one language can’t be applied in another. If you keep comparing languages and try to apply common js/ruby/perl/java/php/whatever concepts in a different language, you’ll often find that it’s well possible, just that the language isn’t seen as being used that way.
This example shows that (in this context) it’s well possible, in a reasonable and elegant way.
April 1st, 2011 at 12:23 pm
[...] JavaScript-style object literals in PHP [...]
April 22nd, 2011 at 11:19 pm
[...] http://www.phpied.com/javascript-style-object-literals-in-php/ If you enjoyed this article, please consider sharing it! [...]
June 25th, 2011 at 6:16 pm
[...] is an obsession for many other developers such Tantek Çelik with his CASSIS or Stoyan Stefanov via JavaScript-style object literals in PHP.As somebody commented already in one or more related posts, “why on earth do not use simply [...]
August 24th, 2011 at 5:16 am
Curso PHP avanzado…
JavaScript-style object literals in PHP / Stoyan’s phpied.com…
November 30th, 2011 at 5:18 am
My shrinks make me impotent. It’s not like I have women to impress.
God’s watching, so you’re the moron.
November 30th, 2011 at 5:39 am
Wow great. Now make cophee script for php
November 30th, 2011 at 6:06 am
I think you can fix the $this reference problem with bindTo
http://php.net/manual/en/closure.bindto.php
Nice article, not that I am going to try to do in php what I do in js
November 30th, 2011 at 8:10 am
Would have been awesome if you started your article with something like “PHP has proper classes, here is how not to use them”
November 30th, 2011 at 8:17 am
Looks very similar to/almost the same of http://lucato.it/php-anonymous-objects
November 30th, 2011 at 12:33 pm
PHP is a truly hideous language. Why not start developing with Node for server-side work and you can forget you ever learnt that horrible mess that is PHP.
Exactly. Why don’t you throw practicality, libraries, community, and support to the wind, and start using a half-baked project like Node, that changed by the hour, is not even at version 1.0, it’s unsuited for tons of tasks, and lack battle-tested usable first/third party libraries??
Facebook should drop PHP pronto, and use Node.
November 30th, 2011 at 1:21 pm
FYI, Arrays in PHP are more lightweight than Objects.
December 4th, 2011 at 4:44 pm
[...] In PHP you would call that an associative array. $fido = array ( ' name ' => " Fido " , ' barks ' => true ) ; From assoc arrays to objects And you can easily make it an object too: var fido = { } ; fido . name = " Fido " ; fido . barks = true ; JavaScript-style object literals in PHP / Stoyan's phpied.com – Vimperator [...]
December 5th, 2011 at 3:14 pm
I’m considering Javascript (and notdejs) not just for web development but also for desktop apps on Windows. As Microsoft is serious about html/js on windows, I guess people like me need to catch up with it. Thanks for the tutorial stoyan.
January 29th, 2012 at 7:06 am
fiverr…
[...]JavaScript-style object literals in PHP / Stoyan’s phpied.com[...]…
March 13th, 2012 at 11:43 pm
daily affirmations…
[...]JavaScript-style object literals in PHP / Stoyan’s phpied.com[...]…
May 14th, 2012 at 8:44 am
“Exactly. Why don’t you throw practicality, libraries, community, and support to the wind, and start using a half-baked project like Node, that changed by the hour, is not even at version 1.0, it’s unsuited for tons of tasks, and lack battle-tested usable first/third party libraries??”
Oh man, oh boy. Oh boy. Oh man.
I won’t feed the troll any more than to say grown languages are for speaking, not for developing with. To lack any kind of consistent design, or sensible reasoning for design choices, is unscientific and ultimately destructive.
August 21st, 2012 at 1:14 am
Stupid PHP…