Open Source Content Management Framework

mRFC 0048: (Mjölnir) Switching codebase to PHP 5.3+

  1. Revision History
  2. Introduction
  3. New Features of PHP 5.3
    1. Closures/Lambda-functions
    2. Namespaces
    3. Late Static Binding (aka LSB)
    4. Garbage collector for cyclic references
    5. Efficient data-structures in SPL
    6. New default extensions: PHAR (PHP Archive), enchant

Revision History

  • 2009-07-02, created by Alexey Zakhlestin

Introduction

On June 30, 2009 PHP 5.3.0 was released. It brings major functionality changes, which would bring a lot of benefits for Midgard-MVC. Midgard-MVC is, currently, a part of Mjölnir release. Mjölnir is not planned to be a LTS-release, but as a first release of midgard-2 for building produciton sites upon.

I propose to switch Mjölnir development to PHP-5.3+ only compatibility. As a result we will get a cleaner, faster and more powerful code. It would be a bad idea to break compatibility after we release Mjölnir. Majority of application-developers wouldn't rely on Mjölnir for quite some time, which gives unix-distributions enough time to include PHP-5.3 in their releases.

New Features of PHP 5.3

Closures/Lambda-functions

In 5.2 and earlier callbacks could be either runtime-compiled (create_function()), which is slow, or you had to define method and pass it's name, which clutters namespace. Anyway, both these cases lack scope-inheritance which limits their usefulness.

5.3 has true closures, which allows usage of functional patterns in php code. First thing which comes to mind is work with arrays: map, reduce, filter, etc. instead of foreach-cycles. But even more interesting pattern is context-aware callbacks. There's a nice example of such callback here

function loadData($url, $handler)
{
     $handler(file_get_contents($url));
}

function sendPageTo($email, $url)
{
    loadData($url, function($data) use ($email) {
        mail($email, "Here's your data", $data);
    });
}

In general, closures give us a whole new dimension of reusability.

Namespaces

This, probably, is the most discussed feature of PHP 5.3. I'll be short: we have use-case for this. Current naming pattern in Midgard-MVC leads to extremely long class-names. Switching to namespaces would make code more compact, more readable and less fragile.

Also, there is an interesting related topic: using exception-model proposed by php.standards initiative. See "PHP Standards and Best Practices for PHP 5.3+ Frameworks and Libraries" document.

Basic idea is, that application should inherit it's exceptions from the standard SPL-exceptions while giving them the same name (but in it's own namespaces)

namespace Midgard;
class RuntimeException extends \RuntimeException();

after that, framework-developers can use usual "throw new RuntimeException();" in code, and application developers can distinguish between exceptions which come from different frameworks:

try {
    // some code
} catch (Midgard\RuntimeException $e) {
    // Midgard-specific handling
} catch (PEAR2\RuntimeException $e) {
    // PEAR-specific handling
} catch (RuntimeException $e) {
    // Generic handling
}

Late Static Binding (aka LSB)

This is a major step ahead in PHP's dynamic nature. My favourite example for this feature is ActiveRecord-like classes. In PHP 5.2 it was possible to define ActiveRecord class with generic methods for loading, creating, updating of database-records. After that, it was possible to inherit another class from it, while not defining class body. Like this, literally:

class Book extends ActiveRecord {}

$book = new Book();
$book->name = 'name';
$book->author = 'author';
$book->save();

ActiveRecord's save() method, in this case, would detect object's class at runtime and figure out what to do dynamically. That's a common knowledge and is really useful. But… It was impossible to do the same with class-methods (aka "static" methods) until now. Class methods couldn't detect the class they were called on. So, in 5.2 it was impossible to implement generic method for the following case:

$books = Book::find_all();

ActiveRecord's find_all() method would only know, that it belongs to ActiveRecord and wouldn't know anything about Book class.

PHP 5.3 introduces 2 things in this regard:

  • get_called_class() function, which returns class, on which the call was made ("Book" in my example)
  • "static::" caller in addition to "self::". "static::" propagates the call-chain to the parent, so __CLASS__ constant would return child's class name.

check PHP Manual for more details

Garbage collector for cyclic references

This one is simple. In PHP 5.2 and earlier, if you had situation where object $a has reference to object $b, while, at the same time, $b has reference to $a the memory they occupy would never be freed (until program termination). This limitation, effectively, killed possibility of having complex long-running php processes. Sooner or later, process would take all available memory and die("in agony").

PHP 5.3 fixes this and gives us ability to write complex daemons in php.

Efficient data-structures in SPL

Starting with PHP 5.3, SPL (Standard PHP Library) gains real value. Until now it was a set of small, helpful, but mostly under-the-hood goodies. 5.3 brings fast implementations of the most common data-structures:

Usual speed difference between this implementation and implementation in PHP is several tens times, at least. They are really fast.

New default extensions: PHAR (PHP Archive), enchant

(spell-checking), intl (unicode-compliant collation + ICU-based formatting)

PHAR let's us pack a library or an application into a single "project.phar" file. That is convenient for distribution and gives speed-boost if you use phar and APC at the same time (APC can use more efficient cache-strategy, when application is packed as a single-file on filesystem level).

Enchant is a generalized extension, which can work with the majority of spell-checking backends. This includes ispell, aspell and even AppleSpell

intl (aka Internationalization extension) is a binding to ICU (International Components for Unicode) library. It provides means for working with unicode-compliant locale's, proper unicode-compliant sorting and unicode-compliant formatting of dates and numbers. That's a necessity in 21-st century and POSIX-locales are way outdated to handle complex cases properly.

Back

Designed by Nemein, hosted by Anykey