I am a programmer and architect (the kind that writes code) with a focus on testing and open source; I maintain the PHPUnit_Selenium project. I believe programming is one of the hardest and most beautiful jobs in the world. Giorgio is a DZone MVB and is not an employee of DZone and has posted 637 posts at DZone. You can read more from them at their website. View Full User Profile

Writing clean code in PHP 5.4

02.22.2012
| 18447 views |
  • submit to reddit

After seven release candidates, it's clear PHP 5.4 is coming: as always the improvements from the previous minor version are many.

At the platform level, new features cannot do harm: it's almost always handy to have a built-in web server or other tools as long as they do not are a pain to maintain for the core developers. But language designers must be more careful: it's possible to bake in features which can be potentially abused (goto anyone?) to write code difficult to understand and to reuse.

Let's look at the new features and score them on two metrics: usefulness, and potential for abuse. I'll try to avoid discussing non-language related matters.

Traits

Traits are the most famous innovation in PHP 5.4: a form of horizontal reuse similar to multiple inheritance and capable of including fields and methods into many different places, in a many-to-many relationship between classes and traits.

Traits and mixins often lead to poor cohesion of the classes using them: objects that expose hundreds of methods simply because they're available and ready to be grabbed in a trait.

First, PHP tries to limit the issues of multiple inheritance by introducing many compile-time checks on traits composition:

  • traits with equally named methods cause a Fatal Error unless there is an explicit conflict resolution (so no silently overwriting of methods is allowed.)
  • Traits are in a separate hierarchy, so they can be composed with each other, but can't borrow code from classes.
  • They support abstract members, forcing a method definition in the composing class; calls to undefined members in exhibiting classes is avoided.
  • The can define properties, but not already existing ones in the exhibiting class.
  • They could originally override legacy constructors, but this potential abuse was recognized as a bug and fixed.

I compare traits to abstract classes, with the same problems: coupling (inheritance is a fixed dependency relationship), poor testability and understandability since you have to look at code in many places. With regard to composition of an interface, that when done right makes you stop at interface boundaries, inheritance may make you jump up and down the hierarchy. But now there are multiple hierarchies to move in.

But I wouldn't throw away inheritance support in the language, because there are some use cases for it even for hardcore OO programmers. The problem is in the majority of cases it's like using a Decorator or a Composite just because it's cool and not because there are forced in the design calling for it.

What we don't want is objects pulling in 300+ methods "just in case" although Java APIs manage do to that without traits (by inheriting from a hierarchy chain of 6-7 superclasses). Thus I like the possibility of exhibiting traits, while I know I won't like much of their actual usage.

Usefulness: 8. Potential for abuse: 8.

Array short notation

Indeed PHP arrays are the glue that keeps a large part of the web together. They are lists, maps and matrices at the same time. And indeed they are probably overused as primitive types, where some Value Object or domain object would fit better.

However, the new notation is not an issue in itself:

[giorgio@Desmond:~]$ php -r 'var_dump([4, 2]);'
array(2) {
  [0]=>
  int(4)
  [1]=>
  int(2)
}
[giorgio@Desmond:~]$ php -r 'var_dump(['key' => 4]);'
array(1) {
  ["key"]=>
  int(4)
}

JavaScript and many other dynamic languages have now the same syntax, so there is no reason to force array() on developers. There is little in this syntax that would influence array usage, which is already very popular.

Usefulness: 8. Potential for abuse: 2.

Array dereferencing

Alessandro Nadalin exposes a simple use case where this features is handy, storing closures in an array:

$callbacks = array('key' => function() { ... }, ...);
$callbacks['key']();

However, while [$field]() and ()[$field] work (and []()[] will), any attempt with two () like ()[]() won't due to syntax errors. These are likely to be violations of the Law of Demeter, thus I'm fine with not supporting never ending dereferencing chains.

Usefulness: 7. Potential for abuse: 4.

Closure and arrays calling, plus type hint

You can call with $variable() not only closures now, but also the classic callbacks like array($object, 'method').

As a result, lots of ifs and boilerplate code can be avoided:

$callback = function($param) use ($object) {
    return $object->method($param);
};

Moreover, the Callable type hint is reserved for this kind of structures. This is polimorphism as its best.

Usefulness: 9. Potential for abuse: 2.

Closure binding and rebinding

$this now does not have to be assigned to $self when creating a closure inside an object; plus, you can access private fields of an object by creating a closure inside it, since the scope would logically allow for that once you are accessing $this:

<?php
class A
{
    private $field;

    public function __construct($value)
    {
        $this->field = $value;
    }

    public function goodClosure()
    {
        return function() {
            echo $this->field, "\n";
        };
    }
}
$a = new A(42);
$goodClosure = $a->goodClosure();
$goodClosure(); // prints 42

Private field references are kept with the class they are defined in, so this is indeed a cohesive solution.

However, Filippo Tessarotto pointed out to me that the new bindTo() method on a closure aims to change the scope it refers to. It can even make private properties accessible by code written outside a class (like in reflection, but it's even easier). This code causes a big wat?

$closure = function() {
    echo $this->field;
};  

$a = new A(42);
$boundClosure = $closure->bindTo($a, $a);
$boundClosure(); // prints 42

Usefulness: 8. Potential for abuse: 10.

Upload progress

This addition allows to track partically uploaded files to inform the user about the percentage of the file arrived at the server. It cannot do harm for code in general: it's limited to uploaded files treatment.

The API is a bit primitive-obsessed (every information is provided into a giant array in $_SESSION, which is itself another array), but there is no potential for surprises. It is in line with the rest of the PHP server environment, providing $_GET and $_POST as superglobal arrays.

Usefulness: 7. Potential for abuse: 2.

Deprecations

All magic quotes and Safe mode functionalities are not only deprecated like in PHP 5.3, but even removed (as the UPGRADING file in PHP 5.4 source tells us.) Other deprecated directives are register_globals, register_long_arrays ($HTTP_POST_VARS? I don't even remember their names).

About databases, ext/sqlite has been removed from the core but SQLite 3 support is still there. The mysql() functions are still included!

Usefulness: 7, since it makes the language less old and provides newcomers to the language with a better default. Potential for abuse: 1, although it has potential for disruption on old websites.

JsonSerializable

By implementing this interface, you make objects acceptable to json_encode(). It's a procedural form of polimorphism, but takes away a step in converting to JSON: PHP is always built with the web in mind, not as a general purpose language. I just hope it isn't implemented by domain objects and everything that moves.

Usefulness: 6. Potential for abuse: 6.

Conclusion

Did I miss a new feature which someone can use to cook spaghetti? Or are the ones cited here so handy for you that their benefits will outweigh the dangers?

Published at DZone with permission of Giorgio Sironi, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Steve Clay replied on Thu, 2012/03/22 - 9:40am

Your code example for "Closure and arrays calling, plus type hint" was not very clear. Otherwise great article.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.