zurück zum Artikel

Was ändert sich mit PHP 5.3?

Sebastian Bergmann, Alexander Neumann

Gut zweieinhalb Jahre nach der Veröffentlichung von PHP 5.2 ist nun mit Version 5.3 die nächste Generation der populären Programmiersprache erschienen. heise Developer stellt die wichtigsten Neuerungen vor.

Gut zweieinhalb Jahre nach der Veröffentlichung von PHP 5.2.0 im November 2006 ist nun mit Version 5.3.0 die nächste Generation der nach Java, C und C++ populärsten Programmiersprache [1] erschienen [2]. In PHP 5.3 stecken aber mehr als zweieinhalb Jahre Entwicklungszeit, haben die PHP-Entwickler doch fast alle Neuerungen, die für PHP 6 gedacht waren, für diese Version vorgezogen. heise Developer stellt die wichtigsten vor.

Namensräume (englisch: Namespaces) sind ein Sprachmerkmal, das viele PHP-Entwickler lange Zeit vermisst haben. Derselbe Name (für eine Konstante, Klasse oder Funktion) lässt sich in unterschiedlichen Namensräumen ohne Konflikt verwenden. So kann man beispielsweise Namenskonflikte zwischen Framework- und eigenem Code vermeiden. Einen Namensraum deklariert man über das Schlüsselwort "namespace". Das muss die erste Anweisung in der Quelltextdatei sein. Alle nach dieser Anweisung deklarierten Konstanten, Klassen und Funktionieren sind dem Namensraum zugeordnet.

    example.php
<?php
namespace project;

const ANSWER = 42;
class SomeClass {}
function doSomething() {}
?>

In dem voranstehenden Beispiel (Datei example.php) deklariert man den Namensraum project. Dieser enthält je eine Konstante, Klasse und Funktion. Innerhalb des Namensraums project lässt sich auf diese Elemente über die lokalen Namen ANSWER, SomeClass und doSomething() zugreifen. Für den Zugriff auf diese Elemente von außerhalb des Namensraums gibt es die folgenden Optionen.

Inkludiert man die Datei example.php in einer anderen PHP-Quelltextdatei, so lässt sich über die vollständig qualifizierten Namen project\ANSWER, project\SomeClass und project\doSomething auf die im Namensraum project in der Datei example.php deklarierten Programmelemente zugreifen.

    <?php
require 'example.php';

print project\ANSWER;
$object = new project\SomeClass;
project\doSomething();
?>

Vollständig qualifizierte Klassennamen kann man mit dem Schlüsselwort use im lokalen Namensraum bekannt machen:

    <?php
require 'example.php';

use project\SomeClass;

$object = new SomeClass;
?>

Alternativ lassen sich vollständig qualifizierte Klassennamen über einen lokalen Alias verwenden:

    <?php
require 'example.php';

use project\SomeClass as Foo;

$object = new Foo;
?>

Der Name eines Namensraums kann das Namensraumtrennzeichen, das Backspace-Zeichen, enthalten. So lassen sich verschachtelte Namensräume abbilden:

    <?php
namespace project\package\subpackage;

class SomeClass {}
?>

Am Rande der php|tek-Konferenz im Mai 2009 in Chicago haben sich Entwickler einiger bekannter PHP-Bibliotheken beziehungsweise -Frameworks getroffen und mit einer Diskussion über Coding-Standards und Namensräume begonnen. Diese lässt sich unter php.net [3] verfolgen und ist jedem Entwickler zu empfehlen, der seinen Code auf Namensräume umstellen möchte.

Kaum ein Sprachmerkmal wurde in der Geschichte von PHP so kontrovers diskutiert wie die Namensräume. Ursprünglich für PHP 5.0 geplant, dann zurückgezogen, halten sie nun in PHP 5.3 Einzug in die Sprache. Man mag sich über Punkte wie "zu wenig und zu spät" oder das Namensraum-Trennzeichen "\" streiten, sollte aber bei allem nicht die Vorteile vergessen.

Ein wesentliches Merkmal der objektorientierten Programmierung ist die dynamische beziehungsweise späte Bindung: Erst zur Laufzeit lässt sich entscheiden, welche Methode bei einem Methodenaufruf (besser: bei einer Nachricht an ein Objekt) tatsächlich auszuführen ist.

In den Vorgängerversionen war die dynamische Bindung nur für Instanzmethoden implementiert, die Bindung für Klassenmethoden also statisch. Dies kann man anhand des nachstehenden Beispiels nachvollziehen:

    <?php
class Base
{
public static function a()
{
print __METHOD__ . "\n";
self::b();
}

public static function b()
{
print __METHOD__ . "\n";
}
}

class Child extends Base
{
public static function b()
{
print __METHOD__ . "\n";
}
}

Child::a();
?>

Base::a
Base::b

Da man self anders als $this bereits in der Kompilierphase ausgewertet und durch den Namen der Klasse ersetzt hat, hat das Überschreiben der Methode in der Kindklasse nicht den gewünschten Effekt. PHP 5.3 bietet nun die Verwendung von static an, um zu notieren, dass für den Aufruf einer Klassenmethode die dynamische Bindung zu verwenden ist:

    <?php
class Base
{
public static function a()
{
print __METHOD__ . "\n";
static::b();
}

public static function b()
{
print __METHOD__ . "\n";
}
}

class Child extends Base
{
public static function b()
{
print __METHOD__ . "\n";
}
}

Child::a();
?>

Base::a
Child::b

Der Programmierer hat es in der Hand, ob er für den Aufruf einer Klassenmethode die dynamische oder statische Bindung verwenden soll.

Vor PHP 5.3 konnte man nur über eine Krücke, nämlich mit create_function(), eine anonyme Funktion (Lambda Function) deklarieren. In PHP 5.3 ist es möglich, eine anonyme Funktion direkt im Quelltext zu notieren:

    <?php
$list = array(22, 4, 19, 78);

usort(
$list,
function ($a, $b) {
if ($a == $b) return 0;
return ($a < $b) ? -1 : 1;
}
);

print_r($list);
?>

Array
(
[0] => 4
[1] => 19
[2] => 22
[3] => 78
)

Diese Notation ist nicht nur deutlich lesbarer, dank ihr ist der PHP-Interpreter nun in der Lage, bereits in der Kompilierphase etwaige Syntaxfehler im Rumpf der anonymen Funktion zu entdecken. Ferner profitieren anonyme Funktionen von einem Bytecode-Cache.

Ebenso wie die Lambda-Funktionen haben Closures ihren Ursprung in der funktionalen Programmierung. Bei ihnen handelt es sich um anonyme Funktionen, die um eine Bindung an externe, sogenannte lexikalische Variablen erweitert sind. Anders als in anderen Programmiersprachen, die Unterstützung für Closures bieten, sind in PHP die lexikalischen Variablen explizit über das Schlüsselwort use zu deklarieren:

    <?php
$string = 'Hello World!';
$closure = function() use ($string) { print $string; };

$closure();
?>

Hello World!

In dem voranstehenden Beispiel bindet man die Variable $string lexikalisch an den Sichtbarkeitsbereich der anonymen Funktion: Wann immer die anonyme Funktion auszuführen ist, gibt sie den Inhalt der Variable $string aus, den diese zum Zeitpunkt der Deklaration der anonymen Funktion hatte.

Im Normalfall erfolgt die lexikalische Bindung derart, dass Änderungen der Variablen keine Auswirkung auf die lexikalische Variable der anonymen Funktion haben. Da das nicht immer gewünscht ist, lässt sich über den &-Operator die lexikalische Bindung per Referenz wählen:

    <?php
$x = 1;
$closure = function() use (&$x) { print $x . "\n"; };
$closure();
$x = 2;
$closure();
?>

1
2

Über anonyme Funktionen und Closures hinaus führt PHP 5.3 das Konzept der Funktionsobjekte ein. Ein Objekt einer Klasse, die eine __invoke()-Methode implementiert, ist aufzurufen, als wäre es eine Funktion:

    <?php
class Example {
public function __invoke() {
print __METHOD__ . "\n";
}
}

$object = new Example;
$object();
?>

Example::__invoke

Auf diese Weise lassen sich beispielsweise Callbacks mit Zustand implementieren.

Als Beispiel für die Vielzahl an Überarbeitungen "unter der Motorhaube" von PHP sei der neue Garbage Collector genannt. Er nutzt den in "Concurrent Cycle Collection in Reference Counted Systems [4]" von IBM vorgestellten Algorithmus. Die PHP-Entwickler hatten ihn im Rahmen des Google Summer of Code 2007 implementiert.

Das Besondere an dem Garbage Collector ist, dass er Objektzyklen erkennt und auflöst. Dem Phänomen der Objektzyklen nähert man sich am besten über ein Beispiel.

    Node.php
<?php
class Node
{
protected $children = array();
protected $parent;

public function addChild(Node $node)
{
$node->setParent($this);
$this->children[] = $node;
}

public function setParent(Node $parent)
{
$this->parent = $parent;
}
}
?>

Das nachstehende Listing erzeugt ein Objekt der Klasse Node, die einen Knoten in einem Baum repräsentiert. Das Objekt erhält im nächsten Schritt über die Methode addChild() einen Kindknoten.

    <?php
require 'Node.php';

$root = new Node;
$root->addChild(new Node);
?>
node1.png

PHP speichert beide Objekte intern (Abb. 1).

Abbildung 1 zeigt, wie PHP die beiden Objekte intern speichert:

Wenn die Variable $root nicht mehr definiert ist, weil man sie per unset() "gelöscht" hat oder weil die Ausführung den Scope verlässt, in dem man $root definiert hat, so ergibt sich mit den PHP-5.3-Vorgängern folgendes Resultat:

    <?php
require 'Node.php';

$root = new Node;
$root->addChild(new Node);
unset($root);
?>
node2.png

Da sich die beiden Node-Objekte gegenseitig referenzieren, können die Referenzzähler nicht 0 werden und die Objekte eignen sich folglich nicht für das Garbage Collection, obwohl man sie nicht mehr verwendet beziehungsweise verwenden kann.

Der neue Garbage Collector in PHP 5.3 erkennt sowohl den Objektzyklus als auch die Tatsache, dass es keine Referenz von außen auf ein Objekt des Objektzyklus gibt. Die Objekte lassen sich so durch den Garbage Collector automatisch löschen.

Besonders bei lang laufenden PHP-Prozessen macht sich der neue Garbage Collector bemerkbar. Beispielsweise hat man bei der Ausführung der PHPUnit-Testsuite der eZ Components [5] eine Verringerung des Speicherbedarfs von 1 GB mit PHP 5.2 auf 100 MB mit PHP 5.3 gemessen, die nur auf den Garbage Collector zurückzuführen ist. Ähnliche Verbesserungen meldet das Doctrine [6]-Projekt, dessen Testsuite sich mit PHP 5.3 20 Prozent schneller und mit 30 Prozent geringerem Speicherbedarf ausführen lässt.

Die PHP-Entwickler haben einige weitere Überarbeitungen am PHP-Interpreter vorgenommen, die über die im Detail beschriebenen Verbesserungen des Garbage Collector hinaus gehen. Diese wirken sich sowohl auf die Ausführungsgeschwindigkeit als auch auf den Speicherverbrauch aus.

benchmark.png

PHP-Benchmark zu unterschiedlichen PHP-5-Versionen (Abb. 3)

Wie aus dem Diagramm in Abbildung 3 abzulesen ist, führt PHP 5.3 den Zend/bench.php-Benchmark ungefähr 1,5-mal so schnell aus wie PHP 5.2 – und fast 4-mal so schnell wie PHP 5.0 (das ungefähr so schnell war wie PHP 4.4).

Zwar handelt es sich um einen "synthetischen" Benchmark, jedoch haben Migrationen von PHP 4 zu PHP 5 in der Praxis vergleichbare Verbesserungen bei realen Anwendungen gezeigt. So konnte beispielsweise die Foto-Plattform Flickr kürzlich die CPU-Last ihrer Server allein durch die Umstellung von PHP 4 auf PHP 5 um 20 Prozent reduzieren.

Mit mysqlnd hält eine für PHP entwickelte und optimierte Implementierung des MySQL-Client/Server-Protokolls in PHP 5.3 Einzug. Lagen die Daten für beispielsweise Ergebniszeilen von Anfragen früher im Speicher von libmysql und in dem von PHP, so belegen sie nun nur noch einmal Speicher, und zwar im von PHP-Prozess verwalteten Speicherbereich. Dies führt beim Umgang mit großen Datenmengen zu deutlich verbessertem Laufzeitverhalten.

mysqlnd wird standardmäßig mit PHP 5.3 ausgeliefert und lässt sich für die unterschiedlichen MySQL-APIs (mysql, mysqli, pdo_mysql) als Ersatz für die unter der GPL stehende libmysql verwenden.

Durch Microsofts Unterstützung schließt PHP unter Windows mit der neuen Version hinsichtlich Funktionsumfang, Performanz und Stabilität im Vergleich zu anderen Betriebssystemen auf. Funktionen, die bislang nur unter Unix verfügbar waren beziehungsweise unter Unix teilweise anders funktionierten, lassen sich nun auf der Microsoft-Plattform verwenden. Den Build-Prozess für PHP unter Windows, den man beispielsweise auch für die Erstellung der offiziellen Binaries für Windows nutzt, haben die PHP-Entwickler entschlackt und modernisiert. PHP funktioniert nun beispielsweise mit der neuesten Generation von Microsofts C-Compilern (VC9, Visual C++ 2008).

Dank der neuen PHAR-Erweiterung unterstützt PHP 5.3 das PHP-Archiv-Format von Haus aus. Dieses an JAR (Java Archive) angelehnte Dateiformat dient dem Verteilen von PHP-Bibliotheken und -Programmen.

Die neue intl-Erweiterungen implementiert die International Components for Unicode (ICU [7]), eine Bibliothek für Unicode-Unterstützung und Internationalisierung, und bietet mit ihren Klassen und Funktionen eine komfortable Unterstützung bei der Internationalisierung von PHP-Anwendungen. PHP 6 wird die zugrunde liegende ICU-Bibliothek für die Unicode-Unterstützung noch stärker in den PHP-Interpreter integrieren.

Die mime_magic-Erweiterung haben die PHP-Entwickler durch die neue fileinfo-Erweiterung mit gebündelter libmagic-Bibliothek ersetzt.

Die Entwickler haben zend.ze1_compatibility_mode ebenso entfernt wie die experimentelle Steuerung der MySQL-Replikation. Unter anderem markierten sie die POSIX (Portable Operating System Interface for Unix)-Regex-Funktionen (stattdessen sollte man die PCRE (Perl Compatible Regular Expressions)-Funktionen verwenden) sowie die Übergabe von Referenzen zur Laufzeit (Argumente, die als Referenz übergeben werden, sind entsprechend zu deklarieren) als "deprecated". Ihre Verwendung führt in PHP 5.3 zu E_DEPRECATED-Warnungen und wird in PHP 6.0 nicht mehr unterstützt sein.

Die Erweiterungen dbase, fbsql, fdf, ncurses, ming, sybase hat man aus der Standarddistribution von PHP entfernt und nach PECL (PHP Extension Community Library) verschoben. Die sybase_ct-Erweiterung, die anstelle von sybase zu verwenden ist, ist hiervon nicht betroffen.

Version 5.3 stellt eine der größten Aktualisierungen und Überarbeitungen in der Geschichte von PHP dar, deren Umfang durchaus mit dem Versionssprung von PHP 4 auf PHP 5 vergleichbar ist. Ähnliche "Upgrade-Schmerzen" sind allerdings diesmal nicht zu erwarten. Hoffen wir, dass das auch für PHP 6 gilt, an dem bereits fleißig gearbeitet wird und das neben vollständiger Unterstützung für Unicode unter anderem eine verbesserte für die horizontale Wiederverwendung von Code durch Traits bringen wird.

Sebastian Bergmann
ist Mitgründer von thePHP.cc (The PHP Consulting Company) und berät Firmen unter anderem in Fragen der Qualitätssicherung in PHP-Projekten.
(ane [8])


URL dieses Artikels:
https://www.heise.de/-227224

Links in diesem Artikel:
[1] http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html
[2] http://php.net/releases/5_3_0.php
[3] http://news.php.net/php.standards/2
[4] http://www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf
[5] http://ezcomponents.org/
[6] http://www.doctrine-project.org/
[7] http://site.icu-project.org/
[8] mailto:ane@heise.de