In almost all languages, chaining method calls on nested objects is either ugly or unsafe. Groovy found an elegant way around it with ?. operator. PHP didn’t. This article shows what can we do about it.
So what’s the problem?
Say you select personal records from a database. You use left joins to connect the Person table with the Address table. You transform the results and put them in your data structures.
Now you want to display Joe’s home phone number. In Groovy, you do this:
contact_list?.get_contact("Joe")?.get_address("Home")?.phone
Short and NPE-proof.
So in PHP you’d like to do this:
$joes_home_phone = $contact_list
->get_contact('Joe')
->get_address('Home')
->phone;
but because you don’t know if Joe has a home phone or if he even exists, you have to do this:
$joes_home_phone = "no home phone";
if (($t = $contact_list->get_contact('Joe')))
if (($t = $t->get_address('Home')))
$joes_home_phone = $t->phone;
Even though the code sample above is already shorter than a naive approach (we’ve cut some lines by using assignments inside the if conditions), it’s still obscured and tedious do write. What other options do we have?
How about the ternary operator?
One alternative to the code above would look like this:
$joes_home_number = ($t = $contact_list) ?
($t = $t->get_contact('Joe')) ?
($t = $t->get_address('Home')) ?
$t->phone : null : null : null;
And here’s another option, using basic logical operators:
($t = $contact_list) &&
($t = $t->get_contact('Joe')) &&
($t = $t->get_address('Home')) &&
($t = $t->phone) || ($t = null);
$joes_home_number = $t;
It seems more concise and, and some people may find it more readable (especially the last example).
However, this is not what logical operators are for. Also if you’re the only programmer on your team, perhaps you could get away with this, but in a group environment this style of writing is usually banned. So that’s not the answer. What is then?
Other’s ideas, of course!
The solution presented below is inspired by Option class from Scala language. If you don’t know Scala, don’t worry. My PHP version of the idea is really simple, and uses couple basic PHP features.
Here’s how to use it:
// Function call chain
$joes_home_phone = Safe::make($contact_list)
->get_contact('Joe')
->get_address('Home') // safe method call
->phone // safe field access
->safe_get("no home phone"); // and dereference
// Array access chain
$joes_home_phone = Safe::make($contact_list)
->contacts['Joe']
->addresses['Home'] // safe array access
->phone // safe field access
->safe_get("no home phone"); // and dereference
We can create longer call chains without any nesting or additional parentheses. The only extra code is at the beginning and at the end of the call chain. How does it work?
The idea here is to wrap result of every method call in a new Safe class instance. Because Safe class overrides the magic method __call(), we can handle cases where the invoked method returns null and allow further chaining.
Accessing fields is handled in a similar fashion. Custom array access relays on ArrayAccess interface implementation.
For another example, consider the following code:
class C1
{
function method1() { return null; }
}
echo Safe::make(new C1)
->method1() // method1 returns null, but
->nonexisting_field // we can still safely do this
->not_an_array[7] // and this
->safe_get("not found");
The code prints “not found” message.
Safe class implementation is rather short, so for more explanation just go ahead and look the the code.
Wrapping up
Of course, this solution is not a free lunch. As you probably guessed, the price for concise and flexible syntax is performance. Simple tests showed that it’s usually 5-8 times slower than piled-up if statements. However, often times PHP code is not a bottleneck (for example when you deal with a database) and for those cases, nicer and more concise code is worth more than a few CPU cycles.
Source code for this article contains complete implementation of the Safe class and some more extensive, ready to run usage examples.

October 8th, 2009 10:31
I know with Entity object is less important, but chained method calls like these are violation of the Law (Suggestion) of Demeter…
October 8th, 2009 11:44
How about using some sort of NullObject for the contact , instead of running multiple conditions to end up using nulls like in:
1.$joes_home_number = ($t = $contact_list) ?
2. ($t = $t->get_contact(‘Joe’)) ?
3. ($t = $t->get_address(‘Home’)) ?
4. $t->phone : null : null : null;
consider returning a NullObject for an empty contact to hold empty data values , thus even if ‘Joe’ doesn’t exist it would still return a chainable NullObject that holds the null values you are using.
Removes all conditions and allows a more natural flow
October 8th, 2009 12:31
@Jonatan: That’s a very good point. Aside from more natural flow it would be much faster too
Unfortunately, null objects have couple major drawbacks. First of all, you need to modify every method that could return null. But what’s worse, you need to modify all client code. That leads to the dilemma: do we return null objects everywhere for consistency? If so, number of classes doubles by definition. There’s also increasing performance penalty attached…
I guess these are some reasons why the NullObject pattern is not that popular in practice. Groovy’s/Java 7 approach is nice because it’s orthogonal and “optional”. That’s what I wanted to achieve here.
@Giorgio: well, if you’re listing contacts in an HTML template, you have to traverse objects hierarchy anyway, so I think this approach doesn’t break anything that wasn’t broken anyway :)