Skip to content

I called Zend_Json::encode(), so WTH are all my properties?

Dear Reader,

Ok, this one is just stupidity on my part but I’m going to post this here so that hopefully others can learn from my mistake.

The problem is simple, JSON encode a PHP object and send it back to the front end. Sounds simple and the last 100 times I wrote this code it was simple. This time, I was too smart for my own good. Here’s the scenario. The object I’m encoding uses PHPs magic functions __get() and __set. __get() and __set() operate on a protected array named (drum roll please) $_data. (Stop me if you’ve heard this one)

class MyClass 
{
    protected $_data;
 
 
    public function __construct()
    {
        $this->_data = array('wifesBirthDay' => '',
                             'nuclearLaunchCode' => '');
 
    } 
 
    public function __get($index)
    {
        if (isset($this->_data[$index])) {
            return $this->_data[$index];
        }
        return null;
    } 
 
    public function __set($index, $value)
    {
        if (isset($this->_data[$index])) {
            $this->_data[$index] = $value;
        }
    } 
 
}

So I instantiate an instance of MyClass and set a few very important properties:

$myObject = new MyClass();
 
$myObject->wifesBirthday = '5/14';
$myObject->nuclearLaunceCode = 'dontPushThisButton';

Now, var_dump($myObject) returns what you think it would, you can see the protected array and the values.

It was at this point that while I was still able to type coherent code, my brain had checked out for the night. The manual for Zend_Json::encode clearly states:

When encoding PHP objects as JSON, all public properties of that object will be encoded in a JSON object.

Obviously my brain simply chose to ignore this detail.

In my mind, the properties existed…right? Cause I could set them; however, since I’m laying it out here for you, it’s easy to see that since $_data is a protected property, it wasn’t getting passed.

Using FireBug (is there a better FireFox extension? I don’t think so) I could see that my PHP was handing back an empty JSON string to be re-constituted on the client side.

The solution, once I realized what was happening, was quite simple. just create an array of the properties you want to pass back.

$payload = array('wifesBirthday'=>$myObject->wifesBirthDay, 'nuclearLaunchCode'=>$myObject->nuclearLaunchCode);
$output = Zend_Json::encode($payload);

That was my first cut and low and behold it works. However, a better solution came to mind.

class MyClass 
{
    protected $_data;
 
    public function __get($index)
    {
        if (isset($this->_data[$index])) {
            return $this->_data[$index];
        }
        return null;
    } // public function __get($index)
 
    public function __set($index, $value)
    {
        if (isset($this->_data[$index])) {
            $this->_data[$index] = $value;
            return true;
        }
        return false;
    } // public function __set($index, $value)
 
    public function getProperties($skip=array())    
    {
        $returnValue = array();
        foreach($this->_data as $key=>$value) {
            if (!in_array($key,$skip)) {
                $returnValue[$key]=$value;
            }
        }
 
        return $returnValue;
    }
}

There, now I can simply write:

$payload = $myObject->getProperties();
$output = Zend_Json::encode($payload);

If I didn’t want to disseminate the nuclear launch codes (I know I’m gonna start getting some weird searches now) I can write:

$payload = $myObject->getProperties(array('nuclearlaunchCode'));
$output = Zend_Json::encode($payload);

So I hope that by embarrassing myself publicly I can help at least one person. (For the record, it really only took me about 2 minutes to trace down the issue.)

Until next time,
(l)(k)(bunny)

=C=

I’ve been published in Dr. Dobbs!

Dear Reader,

Wow, I wrote this article back in May/June and it finally got published! “PHP: The Power Behind Web 2.0“. This was the very first version of the FNN that I wrote. I used the concept in “Flex and PHP: Party in the Front, Business in the Back”.

Thanks to Andi because I’m sure without his name on the article, they wouldn’t have given me a second glance.

That makes two magazine articles this year and I’ll miss my other goal for the year, a book published, by a month or so.

It’s been a productive year.

Until next time,
(l)(k)(bunny)
=C=

New Project – Queuebuddy

Dear Reader,

I’ve been working on a project for a while now and it’s finally ready for testing. Queuebuddy.com started life as a way to help me keep track of movies I want to see but don’t feel like paying to see in the theater. (If you are really curious, email me, I’ll give you what Wife 1.23 refers to as “The Hollywood Speech”) Anyhow, you can register, login and grab the bookmarklet. Then when you are surfing imdb.com you can click on the bookmarklet when you are on a page of a movie you want to see on DVD> When it comes out on DVD.

There’s no fee, there’s no commitment and other than an email when the DVD comes out, we won’t even bug you. So if your interested, drop by and try it out.

Two notes:

  • Since it relies on a bookmarklet, it’s only really usable in FireFox. Apologies to all my Microsoft friends.
  • I’m currently only tracking Region 1 release dates. Since the MPAA and it’s friends deem it necessary to screw over the rest of the world with this stupid region encoding scheme, I will too. (I did have high hopes that Austrailia was going to pass a law a few years ago that made region encoding illegal but I guess too many people decided they couldn’t live unless Hollywood craps in their living rooms because the law failed to pass.)

Oh yeah, as with every web 2.0 property, this is a BETA. There will be bugs and I’m a programmer, not a designer, so it’s pretty ugly right now.

One final note, it”s written using the newly released Zend Framework 1.0. I’m working on a tutorial for DevZone that shows some of the things I learned.

Until next time,
(l)(k)(bunny)

=C=

My first Mashup – Revisited

Dear reader,

A while back, I built a cute little toy that let you track UPS packages on a Google map. My original title for this was “Where the hell is my stuff?” but since I wanted it to be more family friendly, I titled it “My First Mashup“.

Since then, I’ve presented this talk 3 times and each time it gets more fun. However, I feel that this talk is nearing the end of it’s life. So I’ve packaged everything up and put it on the web for all to see. myfirstmashup.com has all the code you need to build your own copy of this. My slides from the most recent version are there as well as working examples should you just want to track a package. (Which, from the database cache I keep of cities, I see some of you are doing.)

If you saw the presentation but wanted the most recent version of the code, it’s there. If you didn’t get a chance to see the presentation, consider this a DIY kit, everything you need is there, just put all the pieces together.

Until next time,
(l)(k)(bunny)

=C=

Internet Explorer XHTTP munges custom headers.

Dear Reader,

Elvis H. Presley! why does Microsoft have to make up their own rules for everything? Why, just for once, can’t they play nice and do things the way everybody else does? Nope, they’ve got to do things just enough different so that I have to make work-arounds.

Ok, here’s the scenario I hit upon tonight and banged head against for about 5 minutes till I saw what was happening.

Using DoJo as my Ajax transport I have the following code in a project.

    sendHeaders = new Object();
    sendHeaders['X-Return-Type'] = 'JSON';
    dojo.io.bind({
        url: "http://example.com/my/api/call/,
        load: displayData,
        headers: sendHeaders

Notice that I set a header “X-Return-Type”. See how nice I was to capitalize the words? That’s because I like them that way. (No major technical reason, I’ll admit, I just like it that way.)

Ok, now, in PHP:

        $headers   = apache_request_headers();
        
        if (!isset($headers['X-Return-Type']) or
            $headers['X-Return-Type']!='JSON') {
                $this->_redirect('/my/other/page');
       }

Ok, pretty straight forward, I set a header and I check for it. The problem is that in IE it’s failing. but why? If you check the headers being sent you’ll find that IE is nice enough to lowercase the header before sending it. This invalidates my isset() test.

So, the answer I came up with (I’m sure there are others) is:

        $headers   = array_change_key_case(apache_request_headers(),CASE_LOWER);
        
        if (!isset($headers['x-return-type']) or
            $headers['x-return-type']!='JSON') {
                $this->_redirect('/my/other/page');
       }

Convert all the keys to lowercase before testing. Ok so it works but c’mon guys, this is just petty. It looks to me like the MS XHTTP object is lowercasing this header before sending it out.

Thank you IE development team for taking the time to break the standards just enough to make me have to waste time tracking something down.

Arrrrgh! I’m going to bed!

Until next time,
(l)(k)(bunny)
=C=

p.s. No, I’ve not tested this in IE 7, I’m trying to avoid loading that steaming pile on my computer. If someone does test, I’d appreciate a comment.

DISCLAIMER: The opinions I express here are mine and mine alone. Go get your own.