Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Geleitwort
Vorwort
1 PEAR – Einführung
2 Authentication
3 Caching
4 Date and Time
5 File Formats
6 HTTP
7 Internationalization
8 Mail
9 Networking
10 PHP
11 Text
12 Web Services
13 Benchmarking
14 Configuration
15 Database
16 File System
17 HTML
18 Images
19 Logging
20 Math
21 Numbers
22 Tools and Utilities
23 XML
24 Selbst Pakete erstellen
25 PECL
Index
Ihre Meinung?

Spacer
 <<   zurück
PHP PEAR von Carsten Möhrke
Anwendung und Entwicklung – Erweiterungen für PHP schreiben
Buch: PHP PEAR

PHP PEAR
798 S., 39,90 Euro
Rheinwerk Computing
ISBN 3-89842-580-0
gp 24 Selbst Pakete erstellen
  gp 24.1 Vorschlag
  gp 24.2 Versionsnummern in PEAR
  gp 24.3 Die Umsetzung des Pakets
    gp 24.3.1 PHP-Version
    gp 24.3.2 Die Klasse PEAR
    gp 24.3.3 Error-Handling
    gp 24.3.4 Dateien und Pfade
    gp 24.3.5 Dokumentation
    gp 24.3.6 Tests
    gp 24.3.7 Beispiele
    gp 24.3.8 package-Datei
    gp 24.3.9 Einen TAR-Ball erstellen


Rheinwerk Computing

24.3 Die Umsetzung des Pakets  downtop

Bei der Erstellung von PEAR-Paketen gibt es einige Punkte zu beachten. In Kapitel 1 haben Sie ja schon einen Teil des PEAR Coding Standards (PCS) kennen gelernt. Ich möchte hier nicht den kompletten Standard erläutern, da dieser sehr ausführlich auf der PEAR-Website unter der URL http://pear. php.net/manual/en/standards.php zu finden ist. Eine deutsche Übersetzung dieses Standards ist zurzeit noch nicht verfügbar. Bitte achten Sie sehr sorgfältig auf die Einhaltung dieses Standards.

Neben dem Coding-Standard sind aber noch weitere Punkte zu beachten.


Rheinwerk Computing

24.3.1 PHP-Version  downtop

Gerade momentan stellt sich die Frage, auf welche PHP-Version Ihr Paket ausgelegt sein sollte. PHP 5 bietet sich aufgrund der neuen Möglichkeiten in der Objektorientierung und einiger praktischer Funktionen an. Allerdings werden Sie feststellen, dass viele PEAR-Entwickler ein wenig allergisch darauf reagieren, wenn ein Paket nur zu PHP 5 kompatibel ist. Oft wird eine PHP 4-Version gewünscht, die PHP 5-kompatibel ist.

Um dieser Anforderung gerecht zu werden, gibt es mehrere Möglichkeiten. Die erste Variante, die allerdings ein wenig mehr Arbeit mit sich bringt, sind zwei komplett unterschiedliche Dateien – eine in der PHP 4- und eine in der PHP 5-Variante. Zwar bedeutet das Mehraufwand, aber Sie können alle Vorteile nutzen, die PHP 5 bietet. Des Weiteren erhalten die Benutzer, die PHP 5 einsetzen, keine unschönen Warnungen durch »veralteten« PHP 4-Code, wenn der Error-Level auf E_STRICT eingestellt ist.

Die zweite Möglichkeit, um beiden Sprachversionen gerecht zu werden, besteht darin, PHP 4-Code zu schreiben, der auch unter PHP 5 funktioniert. Im Allgemeinen sollte das kein Problem sein, da die beiden Versionen ja weitestgehend kompatibel sind.

Auf zwei Punkte möchte ich aber noch einmal hinweisen. Zum einen sollten Sie darauf achten – insbesondere dann, wenn Sie normalerweise PHP 5 nutzen –, dass Objekte bei einer Zuweisung mit einem Gleichheitszeichen in PHP 4 kopiert werden. Das heißt, um den Server zu entlasten, sollten Sie immer eine Referenz zuweisen, wenn nicht explizit eine Kopie erforderlich ist. Das heißt, anstelle von

$obj = new myClass();

nutzen Sie:

$obj =& new myClass();

Für PHP 5 stellt das kein Problem dar. Benötigen Sie allerdings explizit eine Kopie, wird es etwas komplizierter. Um eine Kopie eines Objekts zu erzeugen, ist in PHP 5 das Schlüsselwort clone definiert, das PHP 4 nicht kennt. An dieser Stelle, wie auch an anderen, an denen Sie Schlüsselbegriffe oder Konstrukte benötigen, die in der anderen PHP-Version nicht definiert sind, müssen Sie einen Kunstgriff nutzen. Und zwar ist es an solchen Stellen nötig, die entsprechenden Konstrukte in andere Dateien auszulagern. Leider ist es nicht möglich, Sprachkonstrukte, die in einer Version nicht bekannt sind, mit einem if zu »verstecken«. In einem Paket könnte das so aussehen:

$_mainVersion = substr(PHP_VERSION,0,1); 
require_once("toolsPHP$_mainVersion.php"); 
 
$obj = new  myClass(); 
$obj2 = tools::objCopy($obj);

In diesem Beispiel wird in Abhängigkeit von der genutzten PHP-Version also entweder die Datei toolsPHP4.php oder die Datei toolsPHP5.php inkludiert. In der Version 4 würde die Klasse dann so definiert:

class tools 
{ 
   function objCopy ($obj) 
   { 
      return $obj; 
   } 
}

Wohingegen die Definition der Klasse für PHP 5 so aussehen müsste:

class tools 
{ 
   static public function objCopy ($obj) 
   { 
      return clone $obj; 
   } 
}

Somit ist gewährleistet, dass beide Klassen identisch angesprochen werden können, obwohl sie für unterschiedliche PHP-Versionen gedacht sind.

Der zweite Punkt, der nicht übersehen werden sollte, ist, dass Sie in PHP 5 der Pseudovariable $this innerhalb einer Methode keinen neuen Wert zuweisen können. In PHP 4 wurde diese Möglichkeit teilweise genutzt, um das Auftreten eines Fehlers anzuzeigen. PHP 5 unterstützt diese Möglichkeit nicht mehr.


Rheinwerk Computing

24.3.2 Die Klasse PEAR  downtop

Die Klasse PEAR haben Sie bei der Nutzung von Klassen nur zur Fehlerbehandlung kennen gelernt. Wenn Sie allerdings selbst Pakete erstellen, kann die Klasse Ihnen noch mehr bieten.

Zum Ersten sind hier einige Konstanten zu nennen. Um eine einfache Unterscheidung des genutzten Betriebssystems zu ermöglichen, können Sie auf die Konstanten OS_UNIX und OS_WINDOWS oder die Konstante PEAR_OS zurückgreifen. OS_UNIX bzw. OS_UNIX enthalten einen booleschen Wert. Abhängig vom verwendeten Betriebssystem ist eine der beiden Konstanten true, wohingegen die andere false entspricht. Die Konstante PEAR_OS entspricht entweder dem String 'Unix' oder dem String 'Windows'.

Des Weiteren sind die Konstanten PATH_SEPARATOR und DIRECTORY_SEPARATOR definiert. In PATH_SEPARATOR ist das Zeichen enthalten, das von dem genutzten Betriebssystem verwendet wird, um Pfadangaben voneinander zu trennen. Das ist zum Beispiel dann hilfreich, wenn Sie die Include-Pfade neu setzen wollen.

<?php 
$path = '/usr/lib/php/pear'; 
set_include_path(get_include_path() . PATH_SEPARATOR . $path); 
?>

Die Konstante ist ab Version 4.3.0 zwar auch in PHP deklariert, aber PEAR stellt diese auch zur Verfügung.

In DIRECTOY_SEPARATOR ist das Zeichen enthalten, das genutzt wird, um Verzeichnisnamen in einem Pfad voneinander zu trennen. Das heißt, dass hier üblicherweise ein Slash oder ein Backslash enthalten ist.

Bei den Unterscheidungsmöglichkeiten gilt aber, dass nur zwischen Windows und Unix-Derivaten unterschieden wird. Im Normalfall sollte das ausreichend sein. Möchten oder müssen Sie noch genauer zwischen verschiedenen Unix-Varianten unterscheiden, so können Sie die Klasse OS_Guess nutzen, die Sie in der Datei OS/Guess.php finden. Leiten Sie ein Objekt dieser Klasse ab, wird automatisch versucht, das Betriebssystem zu erkennen. Das Objekt hat dann einen Aufbau bzw. Inhalt wie in dem folgenden Beispiel:

object(OS_Guess)#1 (5) { 
  ["sysname"]=> 
  string(5) "linux" 
  ["nodename"]=> 
  string(3) "www" 
  ["cpu"]=> 
  string(4) "i386" 
  ["release"]=> 
  string(3) "2.4" 
  ["extra"]=> 
  string(8) "glibc2.3" 
}

Im Element 'sysname' ist der Name des Betriebssystems enthalten. 'nodename' ist der Name des Servers, und 'cpu' speichert den Typ des Prozessors. Zurzeit wird hierbei zwischen 'i386' für Intel-Architekturen und 'powerpc' für Macintosh-Rechner bzw. andere Rechner auf Basis eines Power PCs unterschieden.

Der Schlüssel 'release' speichert die Version des Betriebssystems bzw. im Fall von Linux die Version des verwendeten Kernels. 'extra' schließlich ist nicht immer vorhanden. Zurzeit scheint dieser Schlüssel nur unter Linux einen Wert zu enthalten, und zwar handelt es sich um die Version der installierten glibc.

Die Klasse System, die in der Datei System.php enthalten ist, stellt noch einige hilfreiche statische Methoden zur Verfügung. Dabei handelt es sich um »Nachbauten« von Unix-System-Befehlen. Da einige sehr hilfreiche Unix-Befehle nicht nativ in PHP implementiert sind, kann das sehr hilfreich sein. Die wichtigsten Methoden finden Sie im Folgenden.

Die Methode cat() dient dazu, zwei Dateien zusammenzuführen. Sie bekommt zwei Dateinamen in Form eines Strings oder eines Arrays übergeben, liest die beiden Dateien ein und fügt sie zusammen. Wie bei dem System-Befehl gibt es auch hier verschiedene Möglichkeiten, den Befehl zu nutzen. Im einfachsten Fall lesen Sie die Inhalte der beiden Dateien in eine Variable ein:

require_once('System.php'); 
$neu = System::cat('datei1.txt datei2.txt');

In dem Fall wird also einfach der Text der ersten Datei um den der zweiten ergänzt, und beides zusammen wird in der Variable $neu abgelegt.

Alternativ können Sie die beiden Dateien auch zu einer neuen Datei zusammenführen, indem Sie den String 'datei1.txt datei2.txt > datei3.txt' oder den String 'datei1.txt datei2.txt >> datei3.txt' übergeben. Im ersten Fall würde aus den beiden Dateien immer eine neue Datei datei3.txt erstellt. Im zweiten Fall würden die Daten immer an datei3.txt angehängt, wobei die Datei natürlich neu erstellt wird, wenn sie noch nicht existiert.

Möchten Sie die Informationen als Array an die Methode übergeben, ist das kein Problem. In dem Fall würde jeder einzelne Dateiname und das > bzw. das >> in einem Array-Feld als String abgelegt.

Diese Methode, genau wie alle anderen, die noch folgen, generiert übrigens »ganz normale« PHP-Warnungen, wenn etwas schief laufen sollte.

Ein weiterer hilfreicher Befehl ist find(). Mit dieser Methode können Sie nach einer Datei bzw. nach einem Verzeichnis suchen. Auch hier werden die Parameter üblicherweise in Form eines einzelnen Strings übergeben. Als Erstes wird in dem String das Verzeichnis genannt, in dem die Methode mit der Suche beginnen soll. Danach können Sie mit -name den Namen angeben, nach dem gesucht werden soll. Die Namen und Pfade der gefundenen Dateien werden dann als Array zurückgegeben.

require_once('System.php'); 
// Alle Dateien namens php.ini unterhalb von /etc 
$inis = System::find("/etc -name php.ini"); 
// Alle Dateien mit der Endung php unterhalb von /user/net/ 
// suchen 
$dateien = System::find("/user/net/ -name *.php");

Als Platzhalter bei den Dateinamen können Sie neben dem Stern (*) auch den Punkt (.) verwenden, mit dem Sie ein einzelnes Zeichen variabel halten. Da die Methode in alle Verzeichnisse hinabsteigt, die unter dem genannten Verzeichnis liegen, können Sie die maximale Tiefe mit -maxdepth und einer darauf folgenden Zahl beschränken. Mit -type d liefert die Methode nur Verzeichnisse (Directories) zurück, und -type f liefert nur Dateien (Files) zurück.

Benötigen Sie die Information, in welchem Verzeichnis ein Befehl zu finden ist, hilft which() Ihnen weiter. Die Methode bekommt den Namen eines Befehls bzw. Programms übergeben und sucht nach diesem in den Verzeichnissen, die im Suchpfad des Systems abgelegt sind. Wird eine entsprechende Datei gefunden, wird ihr erstes Auftreten inklusive des Pfades als String zurückgegeben. Zurzeit kann die Methode noch Probleme bereiten, wenn der Server den Safe Mode nutzt. Kann eine entsprechende Datei nicht gefunden werden, gibt die Methode false zurück. Das können Sie allerdings beeinflussen, indem Sie der Methode einen zweiten Parameter übergeben. Dieser zweite Parameter ist ein String, der zurückgegeben wird, wenn die Methode die Datei nicht findet. Somit können Sie auf diesem Weg einen anderen Befehl als Rückgabewert festlegen.

Hilfreich sind auch die Methoden zur Arbeit mit temporären Dateien. Möchten Sie den Pfad zum temporären Verzeichnis auslesen, hilft tmpdir() Ihnen weiter. Die Methode ermittelt den Pfad zum temporären Verzeichnis anhand der Umgebungsvariablen und liefert ihn als String zurück.

Um eine temporäre Datei oder ein neues temporäres Verzeichnis anzulegen, ist mktemp() vorgesehen. Die so angelegten Dateien oder Verzeichnisse werden zum Ende der Laufzeit automatisch entfernt. Rufen Sie die Methode ohne Parameter auf, wird eine neue temporäre Datei angelegt, und der Name inklusive des Pfads wird als String zurückgegeben. Üblicherweise wird ein Dateiname mit tmp eingeleitet. Wünschen Sie ein anderes Präfix, können Sie dieses als Parameter an die Methode übergeben.

Soll die Datei in einem bestimmten Verzeichnis angelegt werden, nutzen Sie den Parameter -t und übergeben danach den absoluten Pfad zu dem Verzeichnis. Danach können Sie zusätzlich noch ein Präfix angeben.

Übergeben Sie in dem Parameter-String zusätzlich -d, so wird ein neues Verzeichnis anstatt einer Datei angelegt.

// legt eine temporaere Datei an 
$tmp = System::mktemp(); 
// legt eine temporaere Datei an, die mit TEMP beginnt 
$tmp = System::mktemp("TEMP"); 
// legt ein temporaeres Verzeichnis an 
$tmp = System::mktemp("-d temp_dir"); 
// legt eine temporaere Datei, die mit TEMP beginnt, in /tmp an 
$tmp = System::mktemp("-t /tmp TEMP");

Die letzte wirklich hilfreiche Methode ist rm(), die einen Ersatz für den Befehl rm unter Unix darstellt. rm() kann Dateien oder ganze Verzeichnisse löschen, was PHP nicht direkt unterstützt. In diesem Fall wird der Name der Datei oder des Verzeichnisses als Parameter übergeben. Möchten Sie ein Verzeichnis (inklusive der enthaltenen Dateien) löschen, nutzen Sie den Parameter -r. Da die Methode direkt auf PHPs unlink() zugreift, werden hier keine Wildcards wie * oder . unterstützt. Allerdings können Sie die Namen mehrerer Verzeichnisse oder Dateien, jeweils durch ein Leerzeichen getrennt, übergeben. Kann eine Datei oder ein Verzeichnis nicht gelöscht werden, gibt die Methode false zurück und im Erfolgsfall true.


Rheinwerk Computing

24.3.3 Error-Handling  downtop

Wie Sie mit Fehlern umgehen, die bei der Ausführung von PEAR-Paketen auftreten, haben Sie ja schon gelernt. Nun stellt sich noch die Frage, wie ein solcher Fehler erzeugt wird. Am einfachsten ist es, dazu die Methode throwError() zu nutzen. Die Methode ist in der Klasse PEAR deklariert und liefert ein Objekt der Klasse PEAR_Error zurück.

require_once('PEAR.php'); 
 
class myClass 
{ 
   function foo ($bar = null) 
   { 
      if (null === $bar) 
      { 
         return PEAR::throwError( 
                      'foo ben&ouml;tigt einen Parameter',1); 
      } 
   } 
} 
 
$obj = new myClass(); 
 
$erg = $obj->foo(); 
if (PEAR::isError($erg)) 
{ 
   echo 'Ein Fehler ist aufgetreten.<br />'; 
   echo 'Code: '.$erg->getCode(); 
   die ('<br />Meldung: '.$erg->getMessage()); 
}

Listing 24.1 Fehler mit PEAR generieren

In diesem Beispiel wurde die Methode statisch aufgerufen. Stellt Ihre Klasse eine Subklasse von PEAR dar, ist das natürlich nicht nötig.

throwError() bekommt als ersten Parameter die eigentliche Fehlermeldung übergeben. Der zweite Parameter ist ein Fehlercode, der dem Anwender Ihrer Klasse die Chance gibt zu unterscheiden, ob es sich um einen kritischen oder einen weniger kritischen Fehler handelt. Auch wenn ich es in dem Beispiel nicht gemacht habe, sollten Sie Konstanten definieren, wenn Sie mit verschiedenen Fehlercodes arbeiten, um dem Anwender die Benutzung zu erleichtern.

Zusätzlich können Sie an dritter Stelle noch einen zusätzlichen String, die so genannte Userinfo, übergeben. Hierbei handelt es sich um einen String, der eine Erläuterung zur Nutzung der Methode enthalten kann. Diese Information können Sie später mit getUserInfo() auslesen. Da das ein wenig ungebräuchlich ist, sollten Sie in der Dokumentation darauf hinweisen, wenn Sie diese Möglichkeit nutzen.

Wird die Methode statisch aufgerufen, übernimmt sie die Default-Einstellungen für die Fehlerbehandlung. Bei einem Aufruf aus einem Objekt heraus übernimmt sie das Error-Handling, wie es in dem Objekt definiert ist.

In beiden Fällen gilt aber, dass Sie das Verhalten mithilfe der Methode setErrorHandling()beeinflussen können. Sie bekommt eine Konstante übergeben, die steuert, was mit dem Fehler passiert. Die möglichen Werte mit Erläuterung finden Sie in Tabelle 24.2.


Tabelle 24.2 Verschiedene Fehler-Modi
Konstante Erläuterung
PEAR_ERROR_RETURN Standardeinstellung – es wird ein Fehlerobjekt zurückgegeben.
PEAR_ERROR_PRINT Die Fehlermeldung wird direkt ausgegeben, und zusätzlich wird ein Fehlerobjekt zurückgegeben.
PEAR_ERROR_TRIGGER Generiert einen Fehler mithilfe der PHP-Funktion trigger_error(). In diesem Fall können Sie der Methode einen weiteren Parameter übergeben, mit dem Sie bestimmen können, um welche Art von Fehler es sich handelt. Möglich sind E_USER_NOTICE (Standard), E_USER_WARNING und E_USER_ERROR. Des Weiteren wird ein Fehlerobjekt zurückgegeben.
PEAR_ERROR_DIE Das Programm wird mit der Funktion die() terminiert, und die Fehlermeldung wird ausgegeben. Als zweiten Parameter können Sie einen Text übergeben, der zusammen mit der Fehlermeldung ausgegeben wird. Sehen Sie hier ein %s an der Stelle vor, an der die Fehlermeldung eingefügt werden soll.
PEAR_ERROR_CALLBCK Hiermit können Sie eine Callback-Funktion definieren, die im Falle eines Fehlers aufgerufen wird. Als zweiter Parameter ist dabei der Name der Funktion zu übergeben: setErrorHandling(PEAR_ERROR_CALLBACK, 'callback'). Diese muss einen Parameter akzeptieren, mit dem ein PEAR_Error-Objekt übergeben wird.

Zusätzlich ist noch ein Stapel vorgesehen, um dort Fehler abzulegen. Allerdings würde ich momentan davon abraten, diesen zu nutzen, weil die meisten Anwender von Paketen nicht erwarten, dass dieser Verwendung findet, und damit auch nicht unbedingt umgehen können.


Rheinwerk Computing

24.3.4 Dateien und Pfade  downtop

Für die Erstellung von PEAR-Paketen gilt grundsätzlich »one class per file«, sprich, in einer Datei sollte immer nur eine Klasse definiert werden. Die Namen der Klassen und Dateien hängen dabei voneinander ab. Das Paket HTTP_Client gehört beispielsweise zur Kategorie HTTP. Das heißt, die Klassendatei wird im Verzeichnis HTTP (unterhalb des PEAR-Verzeichnisses) abgelegt und hat den Namen Client.php. Die eigentliche Klasse hat dann den Namen HTTP_Client. Benötigt eine Klasse zusätzliche Dateien, sind diese in einem Verzeichnis abzulegen, das den Namen der Klasse (ohne den Namen der Kategorie) trägt. In diesem Beispiel wären die Daten also unter HTTP/Client/ abzulegen. Auch dabei sind die Namen der Klassen und Dateien entsprechend zu vergeben. Wenn es in diesem Beispiel also eine Klasse mit Hilfsfunktionen geben würde, könnte der Dateiname Tools.php lauten, und die Klasse müsste HTTP_Client_Tools heißen.

Benötigt eine Datei Klassen oder Ähnliches aus einer anderen Datei, muss diese natürlich inkludiert werden. Wichtig ist, dass diese Einbindung immer mit require_once() bzw. include_once() erfolgt, wobei ich Ihnen require_once() empfehlen würde. Würden Sie ein »normales« require() bzw. include() nutzen, könnte es schnell passieren, dass Dateien doppelt eingebunden werden.


Rheinwerk Computing

24.3.5 Dokumentation  downtop

Eine Dokumentation zu erstellen ist meist ein ungeliebtes Thema. Daher sind bei vielen Paketen auch keine Dokumentationen vorhanden. Um Ihr Paket aber überhaupt benutzbar zu machen, sollten Sie für alle Klassen, Konstanten und Methoden DocBlocks in Ihrem Code vorsehen. Auf Basis dieser Blöcke wird dann mithilfe von phpDocumentor eine API-Dokumentation erstellt. Eine Erläuterung zu dem Aufbau der Blöcke finden Sie im Kapitel 22.2 über phpDocumentor. Welche Tags für ein PEAR-Paket als Standard betrachtet werden, können Sie einem Beispiel entnehmen, das Sie unter dieser URL finden: http://pear.php.net/manual/en/standards.header.php.

Das sollte allerdings nicht darüber hinwegtäuschen, dass es ein schöner Zug von Ihnen wäre, eine ordentliche Dokumentation zu erstellen. Dokumentationen für PEAR-Pakete werden im DocBook-Format erstellt. Informationen zum Aufbau entsprechender Dokumentationen, zu Software und Ähnlichem finden Sie hier: http://pear.php.net/manual/en/developers.documentation.php.


Rheinwerk Computing

24.3.6 Tests  downtop

Jeder Release eines Pakets sollte Testdateien enthalten. Diese Testdateien sollten alle Klassen und Methoden testen, die in dem Paket enthalten sind. Oft wird dazu das PHP-Test-Format genutzt, das an der Dateiendung .phpt zu erkennen ist. Alternativ können Sie natürlich auch einen Test auf Basis von PHPUnit2 erstellen. Wie das funktioniert, ist in Kapitel 22.1 dieses Buches erläutert.

Ein Test, der mithilfe einer phpt-Datei durchgeführt werden soll, wird auf der Kommandozeile mithilfe des Befehls pear run-tests test.phpt durchgeführt. Die eigentliche Testdatei hat in diesem Beispiel den Namen test.phpt. Im folgenden Beispiel soll diese Klasse getestet werden:

<?php 
class myClass 
{ 
   private $name; 
 
   public function __construct($name=null) 
   { 
      if (null === $name) 
      { 
         echo "Fehler\n"; 
      } 
      else 
      { 
         $this->name=$name; 
      } 
   } 
 
   public function getName() 
   { 
      echo "Der Name lautet: $this->name\n"; 
      return 1; 
   } 
} 
?>

Listing 24.2 Klasse, die getestet werden soll

Die Klasse wurde in der Datei klasse.php abgelegt und soll getestet werden. Die Test-Datei dazu könnte beispielsweise so lauten:

--TEST-- 
Test von myClass 
--FILE-- 
<?php 
require_once('klasse.php'); 
$obj=new myClass(); 
$obj=new myClass('Paul'); 
$obj->getName(); 
?> 
--EXPECT-- 
Fehler 
Der Name lautet: Paul

Listing 24.3 Code zum Testen der Klasse

Zum Ausführen des Tests rufen Sie dann, wie oben erwähnt, pear run-tests test.phpt auf. Bevor ich den Aufbau der Datei erläutere, möchte ich Sie auf einen wichtigen Punkt aufmerksam machen. Aus der Test-Datei wird eine neue PHP-Datei erstellt und auf der Festplatte gespeichert. Die Datei würde in diesem Fall den Namen test.php heißen. Der Name ist also identisch mit dem Namen der Test-Datei, wobei das t am Ende entfernt wird. Somit sollte die Test-Datei also einen anderen Namen haben als die Klassen-Datei, da diese sonst überschrieben wird.

Der Aufbau der phpt-Datei gliedert sich in verschiedene Abschnitte. Jeder der Abschnitte wird mit einer spezifischen Markierung überschrieben. Hierbei sind die folgenden Markierungen möglich:

--TEST--

  • Nach diesem Token folgt der Name des Tests. An dem Namen können Sie später erkennen, welcher Test fehlgeschlagen ist, wenn mehrere Test-Dateien auf einmal ausgeführt werden.

--SKIPIF--

  • Hiermit kann eine Bedingung übergeben werden, die definiert, ob der Test überhaupt ausgeführt werden soll. Gibt der Code, der nach dieser Anweisung folgt, einen Text aus, der mit skip beginnt, wird der Test nicht durchgeführt. Das kann hilfreich sein, wenn Sie vor dem Test beispielsweise prüfen wollen, ob die Klassen-Datei vorhanden ist.
--SKIPIF--
<?php 
if (false == file_exists('klasse.php')) 
{ 
   echo "skip: Datei nicht gefunden"; 
} 
?>

Sollte die Datei klasse.php in diesem Beispiel nicht gefunden werden, wird der Test übersprungen, und als Grund wird »Datei nicht gefunden« ausgegeben.

--FILE--

  • Nach dieser Anweisung folgt der PHP-Code, der den eigentlichen Test durchführt. Der Test basiert nur auf Ausgaben, die der Code macht. Das heißt, wenn Sie einen bestimmten Rückgabewert erwarten, müssen Sie diesen mit echo, print oder einer vergleichbaren Funktion ausgeben.

--EXPECT--

  • Hiermit werden die erwarteten Ergebnisse definiert. Das heißt, hier muss die exakte Ausgabe zu finden sein, die der Code, der unter --FILE-- steht, produzieren soll. Bitte vergessen Sie dabei keine eventuell vorhandenen Leerzeilen. Ein eventuell vorhandener Zeilenumbruch nach der letzten Zeile ist nicht wichtig.

--GET--

  • Mit dieser Anweisung können Sie Daten übergeben, die normalerweise an die URL angehängt würden, also z. B. Daten, die aus einem Formular stammen, das mit der Methode GET verschickt wurde. Die Daten werden dabei so angegeben, wie es für einen Query-String üblich wäre: vorname=Paulchen&nachname=Panther

--POST--

  • Identisch mit --GET--, nur dass die Übergabe der Daten mit der Methode POST erfolgt.

Das Ausführen eines solchen Tests über die Kommandozeile könnte dann beispielsweise so aussehen:

www:/home/ # pear run-tests 
Running 2 tests 
SKIP Test von myClass [./class.phpt] (reason: : Datei nicht gefunden) 
PASS Test von myClass [./test.phpt] 
TOTAL TIME: 00:00 
1 PASSED TESTS 
1 SKIPPED TESTS

Da in diesem Fall nicht spezifiziert wurde, welche Test-Datei genutzt werden soll, werden alle genutzt, die gefunden werden. In diesem Fall wird class.phpt übersprungen, und test.phpt erfüllt die Testbedingungen.

Diese Tests sind nicht nur hilfreich, wenn Sie ein neues Paket erstellen, sondern besonders dann, wenn Sie ein bereits fertiges Paket überarbeiten. Gerade dann schleichen sich schnell mal Fehler ein, die leicht übersehen werden.


Rheinwerk Computing

24.3.7 Beispiele  downtop

Da Sie bei der Entwicklung Ihres Codes sicher auch das ein oder andere Beispiel nutzen, um zu testen, ob und wie Ihr Code funktioniert, wäre es ein netter Zug, diese Beispiele oder extra erstellte Beispiele dem Paket hinzuzufügen. Gerade dann, wenn Ihre Dokumentation ein wenig spärlich ausfällt, sind solche Dateien sehr hilfreich.


Rheinwerk Computing

24.3.8 package-Datei  downtop

Jedes Paket wird von einer XML-Datei namens package.xml bzw. package2.xml begleitet. In dieser XML-Datei sind alle essenziellen Informationen zu Ihrem Paket enthalten. Der Name package.xml bezieht sich noch auf die Version 1 des Dateiformats, das für diese XML-Datei definiert ist. Mit der Version 1.4 von PEAR wird allerdings die Version 2 des Formats eingeführt. Dateien, die nach der Version 2 des Standards aufgebaut sind, werden package2.xml genannt. Um auf einem möglichst aktuellen Stand zu sein, beziehen sich die nachfolgenden Erläuterungen auf die Version 2 des Formats. Da PEAR 1.4 noch im Alpha-Stadium ist, können sich dabei aber noch Änderungen ergeben. Prüfen Sie bitte unter der URL http://pear.php.net/manual/ en/guide.developers.package2.tags.php, ob die nachfolgenden Erläuterungen noch aktuell sind.

Bei package2.xml handelt es sich um die »erste« Datei in dem TAR-Ball, der Ihre Daten enthält. Das heißt, sie liegt in der obersten Ebene, und alle anderen Dateien liegen in einem Verzeichnis, das sich auf der nächsten Hierarchieebene befindet. Eine solche Datei könnte beispielsweise so beginnen:

<?xml version="1.0"?> 
<package version="2.0" 
   xmlns="http://pear.php.net/dtd/package-2.0" 
   xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 
http://pear.php.net/dtd/tasks-1.0.xsd 
http://pear.php.net/dtd/package-2.0 
http://pear.php.net/dtd/package-2.0.xsd"> 
 <name>PEAR</name> 
 <channel>pear.php.net</channel> 
 <summary>PEAR Base System</summary> 
 <description>The PEAR package contains: 
 * the PEAR installer, for creating, distributing 
   and installing packages 
 * the alpha-quality PEAR_Exception PHP5 error handling mechanism 
 * the beta-quality PEAR_ErrorStack advanced error handling mechanism 
 * the PEAR_Error error handling mechanism 
 </description> 
 <lead> 
  <name>Stig Bakken</name> 
  <user>ssb</user> 
  <email>stig@php.net</email> 
  <active>yes</active> 
 </lead> 
<version> 
  <release>1.4.0a11</release> 
  <api>1.4.0</api> 
 </version> 
 <stability> 
  <release>alpha</release> 
  <api>alpha</api> 
 </stability> 
 <!-- STARK gekuerzt -->

Wie Sie schon an dieser deutlich gekürzten Datei erkennen können, sind in ihr alle Informationen zu finden, die wichtig sind, um das Paket verarbeiten zu können. Neben dem Namen des Pakets, der Beschreibung, den Betreuern und der Liste der Veränderungen pro Release ist hier auch die Information zu finden, wohin die Dateien zu kopieren sind.

Das heißt also, diese Datei beeinflusst nicht nur das Erscheinungsbild der Webseite, sondern beschreibt auch, wohin die enthaltenen Dateien installiert werden.

Das root-Element der Datei ist das Tag <package>. Das Attribut version enthält die Version des Dateiformats, momentan 2.0. Die Informationen zu den Namespaces bzw. die Pfade zu den Schema-Dateien können Sie eins zu eins übernehmen.

Innerhalb der Datei können Sie Ihr Paket dann mit den im Folgenden erläuterten Elementen beschreiben. Die Informationen, welche Elemente obligatorisch sind, stammen aus einer XSD-Datei, wobei sich auch diese noch ändern kann. Die aktuelle Version der XSD-Datei finden Sie unter http://pear.php.net/dtd/ package-2.0.xsd. Bitte beachten Sie, dass das Format auf Basis eines Schemas definiert ist und somit in einigen Fällen die Reihenfolge der Elemente zu beachten ist.

<name> (obligatorisch) – Name des Pakets

<channel> (obligatorisch) – Der Inhalt dieses Elements ist der Name des Kanals, der verwendet werden soll. Zurzeit sind die Kanäle pear.php.net und pecl.php.net definiert. Diese Channels sollen eine deutliche Untergliederung ermöglichen. Weitere Channels können zukünftig verfügbar sein. Sollte Ihr Paket über keinen offiziellen Channel verfügbar sein, sondern vielleicht direkt über Ihre Homepage, nutzen Sie <uri> anstelle von <channel>. In diesem Element ist dann die komplette URI anzugeben. Wichtig dabei ist, dass die Dateierweiterung tgz oder tar nicht mit angegeben werden darf. Das heißt, wenn Sie die Datei foo-1.1.tar unter http://www.example.com/download/ anbieten wollen, dann geben Sie

<uri>http://www.example.com/download/foo-1.1</uri>

an.

<summary> (obligatorisch) – Hierin ist eine einzeilige, kurze Beschreibung enthalten.

<description> (obligatorisch) – Dieses Tag definiert eine Beschreibung, die auf der Homepage des Pakets dargestellt wird. Die Formatierungen, die Sie hier im Text nutzen, werden direkt übernommen.

<lead> (obligatorisch), <developer> (optional), <contributor> (optional), <helper> (optional) – Diese Tags werden genutzt, um zu beschreiben, wer alles an diesem Projekt mitarbeitet. Die Elemente beschreiben die Rolle, die eine Person in einem Projekt übernimmt. <lead> steht also für einen »Projekt-Leiter«, wobei mehrere Lead-Entwickler zulässig sind. Ein Developer ist ein Entwickler, der an dem Projekt mitarbeitet. Der Status »Contributor« ist für Personen vorgesehen, die zu dem Projekt beitragen, also vielleicht Code beisteuern, aktiv beraten oder Ähnliches. Ein Helper schließlich ist ein Helfer, der nicht aktiv an dem Projekt mitarbeitet, sondern Fragen des Teams beantwortet oder vielleicht nur testet oder Ähnliches. Wichtig bei der Nutzung dieser Elemente ist, dass Sie sich strikt an die Reihenfolge halten, wie sie hier genannt ist.

Innerhalb dieser Elemente wird der Name des Entwicklers mit dem Element <name> definiert. Danach folgt sein Username, mit dem er sich beim System anmeldet, in dem Element <user>, und das Element <email> wird genutzt, um die E-Mail-Adresse des Entwicklers anzugeben. Das letzte Element <active> definiert schließlich, ob der Entwickler noch aktiv an dem Projekt mitarbeitet, und darf entweder yes oder no als Wert haben. Alle Elemente müssen genannt werden.

<date> (obligatorisch) – Datum der Veröffentlichung im ISO-Format, also z. B. 2005–06–20.

<time> (optional) – Kann die Uhrzeit der Veröffentlichung im 24-Stunden-Format enthalten.

<version> (obligatorisch) – Dies ist das Element, mit dem Sie die Version des Pakets definieren. In diesem Element sind die Unter-Elemente <release> und <api> erforderlich. In diesen Elementen ist eine Versionsnummer im PEAR-Format anzugeben. Die Release-Nummer bezeichnet hierbei die eigentliche Version des Pakets. Die API-Version ist die Version der Schnittstellen. Daran kann ein Anwender Ihres Pakets erkennen, ob sich von einem Release zum anderen eine Änderung in der API ergeben hat.

<stability> (obligatorisch) – Hiermit wird die Stabilität des Paketes definiert, ob es also produktiv genutzt werden kann oder ob das noch nicht empfehlenswert ist. Auch hier müssen wieder die Elemente <release> und <api> enthalten sein. Beide dürfen einen der Werte devel, alpha, beta oder stable enthalten. Für <release> ist zusätzlich noch der Wert snapshot zulässig.

<licence> (obligatorisch) – Hiermit können Sie festlegen, unter welcher Lizenz Ihr Paket veröffentlicht wird. Der Name der Lizenz, also beispielsweise so etwas wie PHP License, wird als Wert genutzt. Die URI, unter der die Lizenz nachgelesen werden kann, übergeben Sie mit dem Attribut uri.

<notes> (obligatorisch) – Hier können Sie Anmerkungen zu dem Paket übergeben.

<contents> (obligatorisch) – Das Element <contents> definiert, welche Dateien das Paket beinhaltet. Das Element ist recht vielgestaltig, da es sich aus verschiedenen komplexen Typen zusammensetzen kann. Daher werde ich hier nur auf die gebräuchlichste Nutzung eingehen.

Nach dem Element <contents> folgt als Erstes ein <dir>-Element. Mit ihm legen Sie fest, in welchem Verzeichnis sich die Dateien befinden, die installiert werden sollen. Als Attribut wird hier name benötigt, womit der Name des Verzeichnisses festgelegt wird. In den meisten Fällen wird es auch erforderlich sein, dass Sie mit dem Attribut basedir ein Basis-Verzeichnis festlegen, in dem die Dateien installiert werden. Diese Pfad-Angabe ist relativ zum PEAR-Basisverzeichnis. Nach <dir> können entweder weitere <dir>-Elemente folgen, um Unterverzeichnisse zu deklarieren, oder es folgen <file>-Elemente. Sollten Sie noch weitere <dir>-Elemente nutzen, sollten Sie das basedir-Attribut hier nicht mehr angeben. Alle Pfade werden aus dem Tar-Ball übernommen und beziehen sich relativ auf das angegebene basedir.

Für jede Datei ist ein <file>-Element vorzusehen. Dieses muss mindestens über die Attribute name und role verfügen. name enthält den Namen der Datei und kann auch über eine Pfandangabe verfügen, so dass Sie nicht unbedingt verschiedene <dir>-Elemente ineinander verschachteln müssen. Das Attribut role definiert, um was für eine Art von Datei es sich handelt. Zulässig sind dabei die Werte php für eine PHP-Datei, test für eine Test-Datei, script für ein Shell-Script oder eine Batch-Datei, data für zusätzliche Hilfsdateien wie Grafiken oder Ähnliches und doc für Dokumentationsdateien. Des Weiteren werden noch Werte für PECL-Releases unterstützt, die ich hier aber nicht aufgreife.

Optional können Sie mit dem Attribut md5sum noch einen MD5-Hash übergeben. Damit kann das Installationsprogramm dann überprüfen, ob die Datei korrekt erstellt werden konnte. Auch hier ist es optional, mit baseinstalldir ein Installationsverzeichnis anzugeben.

Innerhalb des <file>-Elements können Sie außerdem das <task>-Element nutzen, mit dem noch bestimmte Aufgaben definiert werden können, die mit der Datei durchgeführt werden sollen. Hiermit haben Sie die Möglichkeit, Zeilenenden automatisch konvertieren zu lassen, automatisch Versionsnummern einfügen zu lassen oder Ähnliches. Eine komplette Erläuterung der Möglichkeiten finden Sie unter http://pear.php.net/manual/en/guide.developers .package2.tasks.php.

Die beiden nachfolgenden Code-Fragmente beziehen sich auf eine Datei aus dem Paket PEAR und verhalten sich identisch. Da es sich um das PEAR-Paket selbst handelt, das nicht direkt einer Kategorie zugeordnet ist, enthält basedir das Root-Verzeichnis der PEAR-Installation.

Mit einem <dir>-Element:

<contents> 
   <dir name="/" basedir="/"> 
      <file md5sum="f230d8e07bf87a20bf188863dc8470c0" 
                    name="OS/Guess.php" role="php" /> 
   </dir> 
</contents>

Mit verschachtelten <dir>-Elementen:

<contents> 
   <dir name="/" basedir="/"> 
      <dir name="OS"> 
         <file md5sum="f230d8e07bf87a20bf188863dc8470c0" 
                    name="Guess.php" role="php" /> 
      </dir> 
   </dir> 
</contents>

<dependencies> (obligatorisch) – Hiermit müssen Sie definieren, welche Abhängigkeiten erfüllt sein müssen bzw. erfüllt sein sollten, damit Ihr Paket funktioniert. Erst folgt ein Abschnitt, der definiert, welche Abhängigkeiten erfüllt sein müssen. Dieser wird von <required> und </required> eingeschlossen. Nach dem öffnenden Tag sind mindestens die Elemente <php> und <pearinstaller> anzugeben. Innerhalb der beiden Elemente muss das Element <min> auftauchen, das eine Versionsnummer enthält und definiert, welche Version von PHP bzw. des PEAR-Installationsprogramms mindestens vorhanden sein muss, damit Ihr Paket funktioniert. Zusätzlich können Sie mit <max> eine Obergrenze für die Version festlegen. Mit dem Tag <exclude> ist es noch möglich, eine bestimmte Version auszuschließen.

Danach können Sie optional noch Abhängigkeiten von bestimmten Paketen bzw. Erweiterungen angeben. Die Abhängigkeit von einem Paket wird mit dem <package>-Element angegeben. Das wiederum schließt mindestens den Namen des Pakets mithilfe des <name>-Elements und den Channel, über den es veröffentlicht wird, mit <channel> ein. Darüber hinaus können Sie auch hier wieder <min>, <max> und <exclude> nutzen.

Um zu definieren, welche PHP-Erweiterungen Ihr Paket benötigt, nutzen Sie das Element <extension>, mit dem Sie mithilfe von <name> definieren, welche Erweiterung erforderlich ist. Zusätzlich können Sie auch hier wieder <min>, <max> und <exclude> nutzen, um weitere Spezifikationen vorzunehmen.

<dependencies> 
  <required> 
   <php> 
      <min>4.2</min> 
      <max>6.0.0</max> 
   </php> 
   <pearinstaller> 
      <min>1.4.0a1</min> 
   </pearinstaller> 
   <package> 
      <name>Archive_Tar</name> 
      <channel>pear.php.net</channel> 
      <min>1.1</min> 
      <exclude>1.3.0</exclude> 
   </package> 
   <extension> 
      <name>xml</name> 
   </extension> 
</required> 
</dependencies>

Innerhalb des <dependencies>-Elements können Sie noch mit <optional> einen Abschnitt definieren, in dem optionale Abhängigkeiten von Paketen festgelegt werden. Hier können dann wieder verschiedene <package>-Elemente enthalten sein, die so aufzubauen sind, wie ich weiter oben beschrieben habe.

Zusätzlich können Sie noch Abhängigkeiten von Betriebssystemen oder Hardware-Architekturen definieren, was für PEAR-Pakete aber eher selten Sinn macht.

<changelog> (optional) – Zu guter Letzt möchte ich noch auf das Changelog eingehen, das auch in dieser Datei enthalten ist. In diesem Abschnitt ist für jeden Release kurz beschrieben, welche Änderungen vorgenommen wurden. Jeder Release wird von <release> und </release> eingeschlossen. Optional können Sie hier die Elemente <lead> und <developer> nutzen. Obligatorisch sind allerdings <date>, <version>, <stability>, <license> und <notes> anzugeben. Der Aufbau der Elemente ist dabei identisch wie bei der Nutzung am Anfang der Datei.

Wie gesagt, das sind bei weitem nicht alle Elemente, die in einer package2.xml-Datei genutzt werden dürfen. Nach dem jetzigen Stand der Entwicklung sind es allerdings die wichtigsten und erforderlichen.

Möchten Sie selbst eine entsprechende Datei erstellen, prüfen Sie bitte noch mal, ob es inzwischen eine komplette Dokumentation gibt, bzw. vergleichen Sie diesen Text mit der aktuellen XSD-Datei.


Rheinwerk Computing

24.3.9 Einen TAR-Ball erstellen  toptop

Nachdem Sie alle Dateien erstellt haben, können Sie diese zu einem TAR-Ball zusammenfassen. Dazu wechseln Sie einfach in das Verzeichnis, in dem Sie die Daten abgelegt haben, und nutzen den Befehl pear package. Dieser erstellt den entsprechenden TAR-Ball für Sie.

Für die Unterverzeichnisse in dem TAR-Ball ist dabei die folgende Struktur definiert:

Paketname mit Version 
        |-- Name (für zusätzliche Klassen-Dateien - Optional) 
        |-- data (zusätzliche Dateien, Bilder etc. - Optional) 
        |-- docs (Dokumentation - Erforderlich) 
        |   `-- examples (Beispiele - Erforderlich) 
        |-- misc (Sonstiges – Optional) 
        |-- scripts (Shell-Scripts / Batch-Dateien - Optional) 
        `-- tests (Testdateien – Erforderlich)

Für das Paket DB_NestedSet-1.3.6 würde also das »Paketname mit Version« durch DB_NestedSet-1.3.6 ersetzt. Die Datei package2.xml liegt auf derselben Ebene. In diesem Verzeichnis liegt dann die eigentliche Klassendatei, also NestedSet.php. Das Verzeichnis, das im obigen Beispiel mit Name benannt ist, müsste dann NestedSet heißen. In ihm werden alle Dateien abgelegt, die die Klasse zusätzlich benötigt. Hier können Sie auch noch weitere Verzeichnisse ablegen.

Die anderen Verzeichnisse enthalten die Dateien, wie oben beschrieben.

Nachdem Sie einen entsprechenden TAR-Ball erstellt haben, können Sie ihn auf den PEAR-Server hochladen, und Ihr Release ist fertig.

 <<   zurück
     
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: PHP PEAR
PHP PEAR
Jetzt Buch bestellen!
 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: PHP 5.6 und MySQL 5.7






 PHP 5.6 und
 MySQL 5.7


Zum Rheinwerk-Shop: Einstieg in PHP 5.6 und MySQL 5.6






 Einstieg in PHP 5.6
 und MySQL 5.6


Zum Rheinwerk-Shop: Responsive Webdesign






 Responsive Webdesign


Zum Rheinwerk-Shop: Moderne Websites entwickeln






 Moderne Websites
 entwickeln


Zum Rheinwerk-Shop: MySQL 5.6






 MySQL 5.6


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo








Copyright © Rheinwerk Verlag GmbH 2007
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern