Menu

PHP 7.2: the Pitfalls to Avoid for a Better and Cleaner Code

What are the pitfalls to avoid with this new version of PHP and its new functionalities?

As my previous article on PHP 7 scalar and return types pitfalls, instead of describing the new super cool features of this perfect PHP 7.2, I will describe what can be dangerous for the good health of your application.

As Ward Cunningham stated it: “You know you are working on clean code when each routine you read turns out to be pretty much what you expected.” As you will see, this new PHP version can make your code pretty confusing if you don’t know when to use those new functionalities.

The output will be a beautiful Notice: Undefined property: LemonPie::$wheel.

This new scalar type object allows instances of any class as argument to your wheelCount function. At the end you try to display the number of wheel of a… lemon pie.

I can hear you in my head: “but yes but why he didn’t use a vehicle in there?”.

Well, I think we have the right to use a LemonPie object since the function wheelCounts states that any instance can be used.

This example is trivial but imagine on a large scale application. You need to use a method in a totally different part of your shiny app. You don’t care about the implementation of it, you just want to use it.

However this method has an object as argument type:

What object to pass to this method? Maybe an instance of stdClass. Maybe not. Who knows?

You will have to go through the implementation and try to understand what type this method really expect as argument. It’s annoying and shouldn’t be necessary.

If an error is thrown because you didn’t pass the real type used in the method itself, the error message won’t really describe the root cause of the error.
Look at the example above: the problem is not that the lemon pie has no wheel, we simply shouldn’t pass the object LemonPie as argument!

In short: this object type can bring confusion and doubts.

Let’s come back to our trivial example. What would be a better solution?

Thanks to the dependency inversion principle, it’s now clear what argument the method wheelCounts expect: a Vehicle. Nobody needs to go to the implementation, everything is clearly stated. Even the error message explains the root problem.

But wait! It’s not over. object is not only a scalar type. You can use this object type as return type as well!

This return is confusing, hypothetical on the real nature of this object. A developer shouldn’t have to guess.

I disagree with some of the RFC examples as well: you shouldn’t use any instance of stdClass (like the return of the json_encode function) in your code.

stdClass doesn’t have any meaning. An object should have a behavior and be properly named for everybody to understand its role in the application. You need to decode some json? Use an array or wrap the stdClass instance with a fully qualified class.

Is the object type useless?

At that point you can think this new type shouldn’t have been implemented in PHP 7.2.

Actually it can be very useful.

Let say one of your method can accept indeed any type of object in order to do some general operation on them (freezing / saving in memory / caching / serializing…). For those cases having a type object is better than not having any typehint at all.

Another case I can think of: refactoring a legacy application. If you have a codebase without any typehint, using object return types for some obscure method returning a bunch of different objects can be the first step to sanity.

However on the long term I would create interfaces and split those “methods which can return everything”, throwing away the scalar / return type object. As a rule of thumb, if your methods can accept (or return) multiple types of object, you should first try to split it.

This is the general rule I would follow: you need to specify the object type as narrowly as allowed by the language. You need a Vehicle instance in your method? Specify it clearly by using the Vehicle type.
If in some rare cases you can’t narrow your object types using interfaces, object can be a better solution than no types at all.