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