Was Àndert sich mit PHP 5.3?
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
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.
SpÀte Bindung
SpĂ€te Bindung fĂŒr Klassenmethoden
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.
Lambda-Funktionen, Closures und Functors
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.
Garbage Collector
Garbage Collector
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);
?>
Abbildung 1 zeigt, wie PHP die beiden Objekte intern speichert:
- Es gibt zwei Objekte der Klasse
Node. - Eines der beiden
Node-Objekte lĂ€sst sich ĂŒber die Variable$root"von auĂen" ansprechen. - Die beiden Node-Objekte referenzieren sich gegenseitig.
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);
?>
- Es gibt zwei Objekte der Klasse
Node. - Die beiden
Node-Objekte referenzieren sich gegenseitig. - Die Objekte in diesem Objektzyklus sind "von auĂen" nicht mehr zugreifbar.
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.
Performanz- und Speicherverbrauch-Verbesserungen
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.
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.
MySQL- und Windows-UnterstĂŒtzung
MySQL Native Driver (mysqlnd)
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.
Bessere Windows-UnterstĂŒtzung
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).
Neue Erweiterungen
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.
Fazit
AufrÀumarbeiten
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.
Fazit
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
Copyright © 2009 Heise Medien