Mithilfe der neuen Sprachfeatures von PHP V5 kann die Wartbarkeit und Zuverlässigkeit des Codes deutlich verbessert werden. Durch die Lektüre dieses Artikels erfahren Sie, wie Sie diese neuen Funktionen nutzen können, um in PHP V4 entwickelten Code nach PHP V5 zu migrieren.
PHP V5 hat gegenüber PHP V4 erhebliche Verbesserungen vorgenommen. Neue Sprachfunktionen erleichtern den Aufbau und die Pflege zuverlässiger Klassenbibliotheken. Darüber hinaus trug das Umschreiben der Standardbibliothek dazu bei, PHP besser an andere Web-Redewendungen anzupassen, beispielsweise an die Programmiersprache Java™. Werfen wir einen Blick auf einige der neuen objektorientierten Funktionen von PHP und erfahren Sie, wie Sie vorhandenen PHP V4-Code auf PHP V5 migrieren.
Schauen wir uns zunächst an, wie die neuen Sprachfunktionen und der PHP-Ersteller die Art und Weise verändert haben, wie Objekte mit PHP V4 erstellt werden. Die Idee mit V5 bestand darin, eine industrietaugliche Sprache für die Entwicklung von Webanwendungen zu schaffen. Das bedeutet, die Einschränkungen von PHP V4 zu verstehen, dann bekanntermaßen gute Spracharchitekturen aus anderen Sprachen (wie Java, C#, C++, Ruby und Perl) zu extrahieren und sie in PHP zu integrieren.
Die erste und wichtigste neue Funktion ist der Zugriffsschutz für Klassenmethoden und Instanzvariablen – die Schlüsselwörter public, protected und private. Mit dieser neuen Funktion können Klassendesigner die Kontrolle über die intrinsischen Eigenschaften einer Klasse behalten und gleichzeitig den Benutzern der Klasse mitteilen, auf welche Klassen zugegriffen werden kann und auf welche nicht.
In PHP V4 ist der gesamte Code öffentlich. In PHP V5 können Klassendesigner deklarieren, welcher Code für die Außenwelt sichtbar ist (öffentlich) und welcher Code nur innerhalb der Klasse sichtbar ist (privat) oder nur für Unterklassen der Klasse (geschützt). Ohne diese Zugriffskontrollen wird die Entwicklung von Code in einem großen Team oder die Verteilung von Code als Bibliothek behindert, da Benutzer dieser Klassen wahrscheinlich die falschen Methoden verwenden oder auf Code zugreifen, der private Mitgliedsvariablen sein sollte.
Eine weitere große Neuerung sind die Schlüsselwörter interface und abstract, die eine Vertragsprogrammierung ermöglichen. Vertragsprogrammierung bedeutet, dass eine Klasse einer anderen Klasse einen Vertrag bereitstellt – mit anderen Worten: „Das werde ich tun, und Sie müssen nicht wissen, wie es gemacht wird.“ Alle Klassen, die die Schnittstelle implementieren, halten sich an diesen Vertrag. Alle Benutzer einer Schnittstelle verpflichten sich, nur die in der Schnittstelle angegebenen Methoden zu verwenden. Das Schlüsselwort abstract macht die Arbeit mit Schnittstellen sehr einfach, wie ich später erläutern werde.
Diese beiden Schlüsselfunktionen – Zugriffskontrolle und Vertragsprogrammierung – ermöglichen es großen Programmierteams, reibungsloser mit großen Codebasen zu arbeiten. Diese Funktionen ermöglichen es der IDE auch, einen umfangreicheren Satz sprachintelligenter Funktionen bereitzustellen. In diesem Artikel werden nicht nur verschiedene Migrationsprobleme behandelt, sondern es wird auch einige Zeit darauf verwendet, die Verwendung dieser neuen wichtigen Sprachfunktionen zu erläutern.
Zugriffskontrolle
Um die neuen Sprachfunktionen zu demonstrieren, habe ich eine Klasse namens Configuration verwendet. Diese einfache Klasse enthält Konfigurationselemente für die Webanwendung – beispielsweise den Pfad zum Bilderverzeichnis. Idealerweise befinden sich diese Informationen in einer Datei oder Datenbank. Listing 1 zeigt eine vereinfachte Version.
Listing 1. access.php4
<?php
Klassenkonfiguration
{
var $_items = array();
function Configuration() {
$this->_items[ 'imgpath' ] = 'images';
}
Funktion get( $key ) {
return $this->_items[ $key ];
}
}
$c = neue Konfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Dies ist eine völlig orthodoxe PHP V4-Klasse. Die Mitgliedsvariable enthält die Liste der Konfigurationselemente, der Konstruktor lädt die Elemente und die Zugriffsmethode get() gibt den Wert des Elements zurück.
Nach dem Ausführen des Skripts erscheint der folgende Code in der Befehlszeile:
%php access.php4
Bilder
%
sehr gut! Dieses Ergebnis bedeutet, dass der Code normal ausgeführt wird und der Wert des imgpath-Konfigurationselements normal festgelegt und gelesen wird.
Der erste Schritt bei der Konvertierung dieser Klasse in PHP V5 besteht darin, den Konstruktor umzubenennen. In PHP V5 heißt die Methode zum Initialisieren eines Objekts (Konstruktors) __construct. Diese kleine Änderung wird unten gezeigt.
Listing 2. access1.php5
<?php
Klassenkonfiguration
{
var $_items = array();
function __construct() {
$this->_items[ 'imgpath' ] = 'images';
}
Funktion get( $key ) {
return $this->_items[ $key ];
}
}
$c = neue Konfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Die Änderungen sind dieses Mal nicht groß. Bin gerade auf die PHP V5-Konvention umgestiegen. Der nächste Schritt besteht darin, der Klasse eine Zugriffskontrolle hinzuzufügen, um sicherzustellen, dass Benutzer der Klasse die Mitgliedsvariable $_items nicht direkt lesen und schreiben können. Diese Änderung wird unten dargestellt.
Listing 3. access2.php5
<?php
Klassenkonfiguration
{
private $_items = array();
öffentliche Funktion __construct() {
$this->_items[ 'imgpath' ] = 'images';
}
öffentliche Funktion get( $key ) {
return $this->_items[ $key ];
}
}
$c = neue Konfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Wenn ein Benutzer dieses Objekts direkt auf das Elementarray zugreifen würde, würde der Zugriff verweigert, da das Array als privat markiert ist. Glücklicherweise haben Benutzer herausgefunden, dass die Methode get() die sehr willkommenen Leseberechtigungen bereitstellt.
Um zu veranschaulichen, wie geschützte Berechtigungen verwendet werden, benötige ich eine andere Klasse, die von der Konfigurationsklasse erben muss. Ich habe diese Klasse DBConfiguration genannt und angenommen, dass die Klasse die Konfigurationswerte aus der Datenbank lesen würde. Dieses Setup wird unten gezeigt.
Listing 4. access3.php
<?php
Klassenkonfiguration
{
protected $_items = array();
öffentliche Funktion __construct() {
$this->load();
}
geschützte Funktion load() { }
öffentliche Funktion get( $key ) {
return $this->_items[ $key ];
}
}
Klasse DBConfiguration erweitert Configuration
{
geschützte Funktion Load() {
$this->_items[ 'imgpath' ] = 'images';
}
}
$c = new DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Diese Auflistung zeigt die korrekte Verwendung des geschützten Schlüsselworts. Die Basisklasse definiert eine Methode namens Load(). Unterklassen dieser Klasse überschreiben die Methode „load()“, um Daten zur Tabelle „items“ hinzuzufügen. Die Methode „load()“ ist ein interner Bestandteil der Klasse und ihrer Unterklassen, daher ist die Methode nicht für alle externen Verbraucher sichtbar. Wenn alle Schlüsselwörter privat sind, kann die Methode „load()“ nicht überschrieben werden.
Dieses Design gefällt mir nicht wirklich, aber ich habe es gewählt, weil ich der DBConfiguration-Klasse Zugriff auf das Item-Array gewähren musste. Ich möchte, dass das Elementarray weiterhin vollständig von der Konfigurationsklasse verwaltet wird, sodass diese Klassen beim Hinzufügen anderer Unterklassen nicht wissen müssen, wie das Elementarray verwaltet wird. Ich habe folgende Änderungen vorgenommen.
Listing 5. access4.php5
<?php
Klassenkonfiguration
{
private $_items = array();
öffentliche Funktion __construct() {
$this->load();
}
geschützte Funktion load() { }
geschützte Funktion add( $key, $value ) {
$this->_items[ $key ] = $value;
}
öffentliche Funktion get( $key ) {
return $this->_items[ $key ];
}
}
Klasse DBConfiguration erweitert Configuration
{
geschützte Funktion Load() {
$this->add( 'imgpath', 'images' );
}
}
$c = new DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Arrays von Elementen können jetzt privat sein, da Unterklassen die geschützte Methode add() verwenden, um Konfigurationselemente zur Liste hinzuzufügen. Die Konfigurationsklasse kann die Art und Weise ändern, wie sie Konfigurationselemente speichert und liest, ohne Rücksicht auf ihre Unterklassen. Solange die Methoden „load()“ und „add()“ auf die gleiche Weise ausgeführt werden, sollte die Unterklassenerstellung keine Probleme bereiten.
Für mich ist die zusätzliche Zugriffskontrolle der Hauptgrund, über einen Umstieg auf PHP V5 nachzudenken. Liegt es nur daran, dass Grady Booch gesagt hat, dass PHP V5 eine der vier wichtigsten objektorientierten Sprachen ist? Nein, denn ich habe einmal die Aufgabe angenommen, 100KLOC C++-Code zu pflegen, in dem alle Methoden und Mitglieder als öffentlich definiert waren. Ich habe drei Tage gebraucht, um diese Definitionen zu bereinigen, und dabei habe ich die Anzahl der Fehler erheblich reduziert und die Wartbarkeit verbessert. Warum? Denn ohne Zugangskontrolle ist es unmöglich zu wissen, wie Objekte andere Objekte nutzen, und es ist unmöglich, Änderungen vorzunehmen, ohne zu wissen, welche Hindernisse zu überwinden sind. Bei C++ steht mir zumindest noch der Compiler zur Verfügung. Da PHP keinen Compiler mitbringt, wird diese Art der Zugriffskontrolle noch wichtiger.
Vertragsprogrammierung
Die nächste wichtige Funktion, die Sie bei der Migration von PHP V4 auf PHP V5 nutzen sollten, ist die Unterstützung der Vertragsprogrammierung durch Schnittstellen, abstrakte Klassen und Methoden. Listing 6 zeigt eine Version der Configuration-Klasse, in der PHP V4-Programmierer versucht haben, eine einfache Schnittstelle zu erstellen, ohne das Schlüsselwort interface überhaupt zu verwenden.
Listing 6. interface.php4
<?php
Klasse IConfiguration
{
Funktion get( $key ) { }
}
Klasse Configuration erweitert IConfiguration
{
var $_items = array();
function Configuration() {
$this->load();
}
Funktion laden() { }
Funktion get( $key ) {
return $this->_items[ $key ];
}
}
Klasse DBConfiguration erweitert Configuration
{
Funktion laden() {
$this->_items[ 'imgpath' ] = 'images';
}
}
$c = new DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Die Auflistung beginnt mit einer kleinen IConfiguration-Klasse, die alle von der Configuration-Klasse oder abgeleiteten Klassen bereitgestellten Schnittstellen definiert. Diese Schnittstelle definiert den Vertrag zwischen der Klasse und allen ihren Benutzern. Der Vertrag besagt, dass alle Klassen, die IConfiguration implementieren, mit einer get()-Methode ausgestattet sein müssen und dass alle Benutzer von IConfiguration darauf bestehen müssen, nur die get()-Methode zu verwenden.
Der folgende Code wird in PHP V5 ausgeführt, es ist jedoch besser, das bereitgestellte Schnittstellensystem wie unten gezeigt zu verwenden.
Listing 7. interface1.php5
<?php
Schnittstelle IConfiguration
{
Funktion get( $key );
}
Klasse Configuration implementiert IConfiguration
{
...
}
Klasse DBConfiguration erweitert Configuration
{
...
}
$c = new DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Einerseits können Leser den Betriebsstatus besser verstehen, andererseits kann eine einzelne Klasse mehrere Schnittstellen implementieren. Listing 8 zeigt, wie die Configuration-Klasse erweitert wird, um die Iterator-Schnittstelle zu implementieren, die die interne Schnittstelle für PHP ist.
Listing 8. interface2.php5
<?php
Schnittstelle IConfiguration {
...
}
Klasse Configuration implementiert IConfiguration, Iterator
{
private $_items = array();
öffentliche Funktion __construct() {
$this->load();
}
geschützte Funktion load() { }
geschützte Funktion add( $key, $value ) {
$this->_items[ $key ] = $value;
}
öffentliche Funktion get( $key ) {
return $this->_items[ $key ];
}
öffentliche Funktion rewind() { reset($this->_items);
öffentliche Funktion current() { return current($this->_items);
öffentliche Funktion key() { return key($this->_items);
öffentliche Funktion next() { return next($this->_items);
öffentliche Funktion valid() { return ( $this->current() !== false }
}
Klasse DBConfiguration erweitert Konfiguration {
...
}
$c = new DBConfiguration();
foreach( $c as $k => $v ) { echo( $k." = ".$v."n" }
?>
Die Iterator-Schnittstelle ermöglicht es, dass jede Klasse als Array ihrer Verbraucher erscheint. Wie Sie am Ende des Skripts sehen können, können Sie den foreach-Operator verwenden, um alle Konfigurationselemente im Konfigurationsobjekt zu wiederholen. PHP V4 verfügt nicht über diese Funktionalität, Sie können diese Funktionalität jedoch auf verschiedene Arten in Ihrer Anwendung nutzen.
Der Vorteil des Schnittstellenmechanismus besteht darin, dass Verträge schnell zusammengeführt werden können, ohne dass Methoden implementiert werden müssen. Der letzte Schritt besteht darin, die Schnittstelle zu implementieren, wobei Sie alle angegebenen Methoden implementieren müssen. Eine weitere hilfreiche neue Funktion in PHP V5 sind abstrakte Klassen, die es einfach machen, den Kernteil einer Schnittstelle mit einer Basisklasse zu implementieren und diese Schnittstelle dann zum Erstellen von Entitätsklassen zu verwenden.
Eine andere Verwendung abstrakter Klassen besteht darin, eine Basisklasse für mehrere abgeleitete Klassen zu erstellen, in der die Basisklasse niemals instanziiert wird. Wenn beispielsweise DBConfiguration und Configuration gleichzeitig vorhanden sind, kann nur DBConfiguration verwendet werden. Die Konfigurationsklasse ist nur eine Basisklasse – eine abstrakte Klasse. Daher können Sie dieses Verhalten mit dem Schlüsselwort abstract erzwingen, wie unten gezeigt.
Listing 9. abstract.php5
<?php
abstrakte Klassenkonfiguration
{
protected $_items = array();
öffentliche Funktion __construct() {
$this->load();
}
abstrakte geschützte Funktion Load();
öffentliche Funktion get( $key ) {
return $this->_items[ $key ];
}
}
Klasse DBConfiguration erweitert Configuration
{
geschützte Funktion Load() {
$this->_items[ 'imgpath' ] = 'images';
}
}
$c = new DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
Jetzt führen alle Versuche, ein Objekt vom Typ „Configuration“ zu instanziieren, zu einem Fehler, da das System die Klasse als abstrakt und unvollständig betrachtet.
Statische Methoden und Mitglieder
Eine weitere wichtige neue Funktion in PHP V5 ist die Unterstützung statischer Mitglieder und Methoden für Klassen. Durch die Verwendung dieser Funktionalität können Sie das beliebte Singleton-Muster verwenden. Dieses Muster ist ideal für die Configuration-Klasse, da die Anwendung nur ein Konfigurationsobjekt haben sollte.
Listing 10 zeigt die PHP V5-Version der Configuration-Klasse als Singleton.
Listing 10. static.php5
<?php
Klassenkonfiguration
{
private $_items = array();
static private $_instance = null;
statische öffentliche Funktion get() {
if ( self::$_instance == null )
self::$_instance = new Configuration();
return self::$_instance;
}
private Funktion __construct() {
$this->_items[ 'imgpath' ] = 'images';
}
öffentliche Funktion __get( $key ) {
return $this->_items[ $key ];
}
}
echo( Configuration::get()->{ 'imgpath' }."n" );
?>
Das Schlüsselwort static hat viele Verwendungsmöglichkeiten. Erwägen Sie die Verwendung dieses Schlüsselworts, wenn Sie auf globale Daten für alle Objekte eines einzelnen Typs zugreifen müssen.
Magic-Methode
Eine weitere große neue Funktion in PHP V5 ist die Unterstützung von Magic-Methoden, die es Objekten ermöglichen, die Schnittstelle des Objekts schnell zu ändern – zum Beispiel das Hinzufügen von Mitgliedsvariablen für jedes Konfigurationselement im Konfigurationsobjekt. Es ist nicht erforderlich, die Methode get() zu verwenden. Suchen Sie einfach nach einem bestimmten Element und behandeln Sie es wie unten gezeigt als Array.
Listing 11. magic.php5
<?php
Klassenkonfiguration
{
private $_items = array();
function __construct() {
$this->_items[ 'imgpath' ] = 'images';
}
Funktion __get( $key ) {
return $this->_items[ $key ];
}
}
$c = neue Konfiguration();
echo( $c->{ 'imgpath' }."n" );
?>
In diesem Beispiel habe ich eine neue __get()-Methode erstellt, die immer dann aufgerufen wird, wenn der Benutzer nach einer Mitgliedsvariablen für das Objekt sucht. Der Code innerhalb der Methode verwendet dann das Array von Elementen, um den Wert zu finden und diesen Wert zurückzugeben, als ob es dort eine Mitgliedsvariable speziell für dieses Schlüsselwort gäbe. Unter der Annahme, dass es sich bei dem Objekt um ein Array handelt, können Sie am Ende des Skripts sehen, dass die Verwendung des Konfigurationsobjekts so einfach ist wie das Ermitteln des Werts von imgpath.
Bei der Migration von PHP V4 auf PHP V5 müssen Sie sich dieser Sprachfunktionen bewusst sein, die in PHP V4 überhaupt nicht verfügbar sind, und Sie müssen Klassen erneut validieren, um zu sehen, wie sie verwendet werden können.
Ausnahmen
beenden diesen Artikel schließlich mit der Einführung des neuen Ausnahmemechanismus in PHP V5. Ausnahmen bieten eine völlig neue Möglichkeit, über die Fehlerbehandlung nachzudenken. Alle Programme erzeugen zwangsläufig Fehler – Datei nicht gefunden, nicht genügend Speicher usw. Wenn keine Ausnahmen verwendet werden, muss ein Fehlercode zurückgegeben werden. Bitte schauen Sie sich den PHP V4-Code unten an.
Listing 12. file.php4
<?php
Funktion parseLine( $l )
{
// ...
return array( 'error' => 0,
data => array() // Daten hier
);
}
Funktion readConfig( $path )
{
if ( $path == null ) return -1;
$fh = fopen( $path, 'r' );
if ( $fh == null ) return -2;
while( !feof( $fh ) ) {
$l = fgets( $fh );
$ec = parseLine( $l );
if ( $ec['error'] != 0 ) return $ec['error'];
}
fclose( $fh );
0 zurückgeben;
}
$e = readConfig( 'myconfig.txt' );
if ( $e != 0 )
echo( "Es ist ein Fehler aufgetreten (".$e.")n" );
?>
Dieser Standard-Datei-E/A-Code liest eine Datei, ruft einige Daten ab und gibt einen Fehlercode zurück, wenn Fehler auftreten. Ich habe zwei Fragen zu diesem Skript. Der erste ist der Fehlercode. Was bedeuten diese Fehlercodes? Um herauszufinden, was diese Fehlercodes bedeuten, müssen Sie ein weiteres System erstellen, um diese Fehlercodes in aussagekräftige Zeichenfolgen abzubilden. Das zweite Problem besteht darin, dass das Rückgabeergebnis von parseLine sehr kompliziert ist. Ich brauche es nur, um Daten zurückzugeben, aber es muss tatsächlich einen Fehlercode und Daten zurückgeben. Die meisten Ingenieure (ich eingeschlossen) werden oft faul und geben einfach Daten zurück und ignorieren Fehler, weil Fehler schwer zu verwalten sind.
Listing 13 zeigt, wie klar der Code bei der Verwendung von Ausnahmen ist.
Listing 13. file.php5
<?php
Funktion parseLine( $l )
{
// Analysiert und löst eine Ausnahme aus, wenn ungültig
return array(); // Daten
}
Funktion readConfig( $path )
{
if ( $path == null )
throw new Exception( 'bad argument' );
$fh = fopen( $path, 'r' );
if ( $fh == null )
throw new Exception( 'Datei konnte nicht geöffnet werden' );
while( !feof( $fh ) ) {
$l = fgets( $fh );
$ec = parseLine( $l );
}
fclose( $fh );
}
versuchen {
readConfig( 'myconfig.txt' );
} Catch(Ausnahme $e) {
echo( $e );
}
?>
Ich muss mir keine Gedanken über Fehlercodes machen, da die Ausnahme beschreibenden Text für den Fehler enthält. Ich muss auch nicht darüber nachdenken, wie ich den von parseLine zurückgegebenen Fehlercode aufspüren kann, da die Funktion nur dann einen Fehler auslöst, wenn einer auftritt. Der Stapel erstreckt sich bis zum nächsten Try/Catch-Block, der sich am Ende des Skripts befindet.
Ausnahmen werden die Art und Weise, wie Sie Code schreiben, revolutionieren. Anstatt sich mit Fehlercodes und Zuordnungen herumzuschlagen, können Sie sich auf die Fehler konzentrieren, die Sie behandeln möchten. Ein solcher Code ist einfacher zu lesen und zu warten, und ich würde Sie sogar dazu ermutigen, eine Fehlerbehandlung hinzuzufügen, da sich dies normalerweise auszahlt.
Fazit
Die neuen objektorientierten Funktionen und die Hinzufügung der Ausnahmebehandlung liefern starke Gründe für die Migration von Code von PHP V4 auf PHP V5. Wie Sie sehen, ist der Upgrade-Prozess nicht schwierig. Die Syntax, die sich auf PHP V5 erstreckt, fühlt sich genauso an wie PHP. Ja, diese Syntax stammt aus Sprachen wie Ruby, aber ich denke, sie funktionieren sehr gut zusammen. Und diese Sprachen erweitern den Umfang von PHP von einer Skriptsprache für kleine Websites zu einer Sprache, die zur Vervollständigung von Anwendungen auf Unternehmensebene verwendet werden kann.