quakenet:#php Tutorial

Author: Progman, zuletzt bearbeitet von sica @ 2005/02/19 20:10:08

Bitte beachten Sie, dass die Tutorialkapitel zusammenhängen. Wenn sie direkt auf ein Kapitel verlinkt wurden müssen Sie gegebenenfalls die vorherigen Kapitel auch lesen. Achten Sie beim lesen darauf, dass Sie kein Kapitel überspringen.

MySQL-Query Klasse

  1. Warum eine Klasse
  2. Layout der Klasse
  3. Code der Klasse
  4. Beispiel für die Benutzung

1. Warum eine Klasse

Nun erstellen wir ein Beispielklasse in Verbindung mit MySQL. Um ein MySQL-Query zu senden haben wir immer die Funktion mysql_query verwendet. Dann hatte wir noch eine Fehlerabfrage eingebaut. Und als letzes noch, wenn es sich um einem SELECT-Befehl handelte, ein mysql_fetch_assoc Befehl eingebaut. Diese Funktionsaufrufe werden wir in der Klasse benutzen. Mit der Klasse stellen wir eine Sammlung von Funktionen bereit.

Es ist natürlich Möglich sich fertige Klassen für Datenbankzugriffe bei Google.com herunterzuladen oder die PEAR::DB Klasse zu benutzen. Aber dadurch lernen wir nicht OOP.

Für die, die schon OOP können (Hallo et *wink*): Ich will jetzt nix großartiges mit extremen Vererbungen und Überladungen erstellen. Es kann deshalb sein, dass die Klasse nicht so nach Standard XY aussieht. Falls jemand meint, die Klasse wäre total unter aller sau, der kann das in der Feedback-Mail oder im Channel #php/QNet sagen.

2. Layout der Klasse

"Was muss die Klasse alles können?" Das ist die erste Frage die man sich stellt, wenn man eine Klasse erstellen möchte. Also, diese Klasse soll einen MySQL-Query an die aktuell offenen MySQL-Verbindung senden. D.h. dass die Klasse nicht für Multi-MySQL-Verbindungen gedacht ist. Ich persönlich arbeite nicht mit mehrere MySQL-Datenbanken gleichzeitig im PHP-Script. Hier noch weitere Punkte was die MySQL Datenban leisten soll.

  1. Der MySQL-Query soll über den Konstruktor ausgeführt werden. Die Definition sieht dann so aus.

    Query(string mysqlquery)
                    

    Diese Funktion, oder besser gesagt Methode, kann keinen Wert zurückliefern, da es sich um den Konstruktur handelt. Diese Methode liefert ja grob gesagt das Objekt der Klasse zurück (Dies läuft intern wahrscheinlich ganz anders ab, aber so ist es verständlich).

  2. Die Klasse muss eine Methode bereitstellen, die sagt, ob ein Fehler im Query aufgetreten ist. Diese Methode definiere ich mal so:

    bool error()
                    
  3. Die nächste Methode liefert uns den Fehlercode und dessen Beschreibung zurück.

    string getError()
                    
  4. Dann brauchen wir eine Methode, die uns sagt, wieviele Datensätze in der Ergebnistabelle bei einem SELECT-Befehl sind.

    int numRows()
                    
  5. Um natürlich die Daten aus der Datenbank zu lesen brauchen wir eine Methode die die Funktion mysql_fetch_assoc ausführt und zurückliefert.

    mixed fetch()
                    

    mixed deshalb, weil die mysql_fetch_assoc Funktion auch false zurückliefern kann.

  6. Zum Schluss erstellen wir noch eine Methode, die die Resourcen in der MySQL-Datenbank freigibt und das Objekt löscht. Dadurch bereinigen wir den Speicher der MySQL-Datenbank.

    void free()
                    

Diese Klasse kann man noch total verkomplizieren. Man kann eine extra Error-Klasse erstellen, von der ein Objekt zurückgeliefert wird wenn der MySQL-Query fehlgeschlagen ist. Aber wir machen hier erstmal einfaches OOP.

Die Methoden der Klasse sind dann alle wie folgt definiert:

// Konstruktor(en)
Query(string mysqlquery)

// Methoden
bool error()
string getError()
mixed fetch()
int numRows()
void free()
        

Über die Eigenschaften der Klasse brauchen wir uns eigentlich keine Gedanken machen. Denn auf die Eigenschaften einer Klasse sollte man nie direkt zugreifen.

3. Code der Klasse

Nun schreiben wir unsere Klasse Query.

<?php                                   
    
class Query
    
{
        function
Query($sql)
        {
        }
        
        function
error()
        {
        }
        
        function
getError()
        {
        }
        
        function
fetch()
        {
        }
        
        function
numRows()
        {
        }
        
        function
free()
        {
        }
    }
?>

Dies ist unser Grundgerüst. Als erstes bearbeiten wir den Konstruktor. Den übergebenene SQL-Query speichern wir erst in eine Variable, die zur Klasse gehört, sprich wir müssen $this benutzen. Dann senden wir den Query ab und wir speichern die Resource-ID ebenfalls in der Klasse, damit wir später mit fetch darauf zugreifen können. Natürlich darf die Fehlerabfrage nicht fehlen, doch diese müssen wir etwas umschreiben. Denn wir wollen nicht einfach das Script sterben lassen, sonder besser darauf reagieren. Falls ein Fehler aufgetreten ist muss dieser schon im Konstruktor abgerufen werden. Würden wir die Fehlermeldung erst in der Methode error oder getError abrufen, so kann es sein, dass in der Zwischenzeit andere MySQL-Querys ausgeführt wurden. Und dann holen wir uns die Fehlermeldung von diesen MySQL-Query, falls dieser ein Fehler erzeugt hatte. Der Programmcode vom Konstruktor sieht nun so aus:

<?php
    
function Query($sql)
    {
        
// Query in der Klasse speichern
        
$this->_sql = trim($sql);
        
$this->_result = mysql_query($this->_sql);
        if(!
$this->_result)
        {
            
$this->_errno = mysql_errno();
            
$this->_error = mysql_error();
        }        
    }
?>

Da wir auf Eigenschaften der Klasse zugreifen, müssen wir diese auch vorher definieren. In PHP ist es zwar Möglich die Klasse um Eigenschaften zu erweitern, aber es gibt Probleme, wenn wir mit einer Methode (z.B. getError()) auf eine Eigenschaft ($_error/$_errno) zugreifen, die es z.B. gar nicht gibt (Der Query war erfolgreich und die Error-Eigenschaften wurden deshalb nicht gesetzt). Wir definieren nun die Eigenschaften der Klasse.

<?php
    
class Query
    
{
        var
$_sql = "";
        var
$_result = 0;
        var
$_errno = 0;
        var
$_error = "";
                
        function
Query($sql)
        
// ...
    
}
?>

Was auffällt ist der Unterstrich bei jedem Variablennamen. Dies hat jetzt nix mit den Superglobals wie $_GET oder $_POST zu tun. In PHP4 gibt es keine Unterscheidung zwischen öffentlichen und nicht-öffentlichen Eigenschaften und Methoden. Dort sind alle Methoden und Eigenschaften für alle zugänglich. Man spricht auch davon, dass sie public sind. In PHP5 plant man, Schlüsselwörter wie public und private einzuführen, um Methoden oder Eigenschaften entsprechend von außen zugänglich zu machen oder nicht. In PHP4 gibt es diese Unterscheidung nicht. Deshalb schreibt man bei den Methoden und Eigenschaften ein Unterstrich davor, um zu kennzeichen, dass diese Methode oder Eigenschaft nicht von außen drauf zugegriffen werden darf bzw. soll.

Nun schreiben wir die Methoden error und getError.

<?php
    
function error()
    {
        
// Result-ID in einer tmp-Variablen speichern
        
$tmp = $this->_result;
        
        
// Variable in boolean umwandeln
        
$tmp = (bool)$tmp;
        
        
// Variable invertieren
        
$tmp = !$tmp;
        
        
// und zurückgeben
        
return $tmp;
    }
?>

Da die Methode entweder true oder false zurückliefern soll müssen wir erst die Result-ID in einen boolischen Wert umwandeln. Danach invertieren wir das Ergbnis der Umwandlung, da eine Result-ID ungleich 0 ja kein Fehler ist. Danach wird der Wert, der nun true oder false ist, zurückgeliefert.

Die Methode, die den Fehlerstring zurückliefert, sieht so aus.

<?php
    
function getError()
    {
        if(
$this->error()) {
            
$str  = "Anfrage:\n".$this->_sql."\n";
            
$str .= "Antwort:\n".$this->_error."\n";
            
$str .= "Fehlercode: ".$this->_errno;
        } else {
            
$str = "Kein Fehler aufgetreten.";
        }
        return
$str;
    }
?>

Da in beiden Fällen ein String zurückgeliefert wird, der in der Ausgabe vielleicht stören könnte, sollte man den Wert der getError-Methode nur dann ausgeben, wenn auch wirklich ein Fehler vorhanden ist.

Die fetch-Methode sieht so aus.

<?php
    
function fetch()
    {
        if(
$this->error()) {
            echo
"Es trat ein Fehler auf. Bitte überprüfen sie ihr\n";
            echo
"MySQL-Query.\n";
            
$return = null;
        } else {
            
$return = mysql_fetch_assoc($this->_result);
        }
        return
$return;
    }
?>

Falls die fetch-Methode trotz fehlerhaftem Query aufgerufen wird, erzeugt das Script eine Fehlermeldung. Es ist natürlich auch möglich, dass Script sofort 'sterben' zu lassen. Ihr könnt aber auch garkeine Fehlermeldung ausgeben, doch dann findet man ggf. den Fehler nicht.

Nun kommt die numRows-Methode.

<?php
    
function numRows()
    {
        if(
$this->error()) {
            
$return = -1;
        } else {
            
$return = mysql_num_rows($this->_result);
        }
        return
$return;
    }
?>

Wenn kein Fehler auftrat, wird die Anzahl der Zeilen in der Ergebnistabelle gelesen. Sonst wird -1 zurückgeliefert.

Als letzes kommt nun die free-Methode, die den Speicher in der MySQL-Datenbank freigibt.

<?php
    
function free()
    {
        
// Speicher freimachen
        
mysql_free_result($this->_result);
    }
?>

Die Klasse kann man sich aus dem Scriptarchiv herrunterladen.

4. Beispiel für die Benutzung

Wir erstellen nun eine neue Datei mit dem Namen classes.php. Dort speichern wir unsere Klassendefinition ab. Diese Datei müssen wir dann nur noch includen. Dies machen wir indem wir einfach unsere config.php entsprechend erweitern.

Nun schreiben wir ein Test PHP-Script und nennen es entsprechend test.php. In der Includen wir die Konfigurationsdatei und bauen eine Verbindung zum MySQL-Server auf.

<?php
    error_reporting
(E_ALL);
    include
'config.php';
    
    @
mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS) OR die(mysql_error());
    
mysql_select_db(MYSQL_DATABASE) OR die(mysql_error());

    echo
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
    echo
"         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
    echo
"<html>\n";
    echo
"    <head>\n";
    echo
"        <title>Meine Seite</title>\n";
    echo
"        <link rel=\"stylesheet\" type=\"text/css\" href=\"page.css\" />\n";
    echo
"        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n";
    echo
"    </head>\n";
    echo
"    <body>\n";

    echo
"    </body>\n";
    echo
"</html>\n";

Nun senden wir ein Query an die Datenbank. Dies machen wir mit unsere neuen Klasse. Im Konstruktor geben wir den MySQL-Query an.

<?php
    error_reporting
(E_ALL);
    include
'config.php';
    
    @
mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS) OR die(mysql_error());
    
mysql_select_db(MYSQL_DATABASE) OR die(mysql_error());
    
    echo
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n";
    echo
"         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
    echo
"<html>\n";
    echo
"    <head>\n";
    echo
"        <title>Meine Seite</title>\n";
    
//echo "        <link rel=\"stylesheet\" type=\"text/css\" href=\"page.css\" />\n";
    
echo "        <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />\n";
    echo
"    </head>\n";
    echo
"    <body>\n";

    
$sql = "SELECT
                Titel,
                DATE_FORMAT(Datum,'"
.DATE_STYLE."') AS Changedatum
            FROM
                news
            ORDER BY
                Datum DESC;
            LIMIT
                10;"
;
    
$newsview = new Query($sql);
    if(
$newsview->error()) {
        echo
"<pre>\n";
        echo
$newsview->getError();
        echo
"</pre>\n";
        echo
"</body>\n";
        echo
"</html>\n";               
        die();
    }
    
    echo
"<p>\n";
    echo
"    Newsübersicht\n";
    echo
"</p>\n";
    echo
"<ol>\n";
    while (
$row = $newsview->fetch()) {
        echo
"<li>\n";
        echo
$row['Titel']."@".$row['Changedatum']."\n";
        echo
"</li>\n";
    }
    echo
"</ol>\n";
    
$newsview->free();
    unset(
$newsview);
    
// Lieber mal das Objekt löschen.
    
    
echo "    </body>\n";
    echo
"</html>\n";

Dieses kleine Script erstellt nun eine Übersicht der letzen 10 Newsbeiträge. Dies macht es mit der Query-Klasse. Query wird gesendet, Ergebnis wird geprüft, Ergebnis wird ausgegeben und Objekt wird zerstört. Dies ist ein sehr einfaches Beispiel für den Gebrauch dieser Klasse. Die Methode numRows() habe ich nun garnicht aufgerufen, da mir dazu grad kein Beispiel eingefallen ist.

Fragen zum aktuellen Thema

  1. Wie kennzeichnet man in PHP4 Methoden/Eigenschaften als Private und Public?
Wie kennzeichnet man in PHP4 Methoden/Eigenschaften als Private und Public?

Wenn man vor dem Namen der Methode/Eigenschaft ein Unterstrich schreibt, so heißt das, dass diese Methode/Eigenschaft nur aus der Klassen herraus zugegriffen werden soll. PHP4 ist es letzendlich egal, wie die Methode/Eigenschaft heißt. Aber der Programmiere kann erkennen: "Oh, auf die Methode/Eigenschaft darf ich nicht zugreifen". Diese Kennzeichnung mit dem Unterstrich wird z.B. in dem PEAR-Standard - Namenskonventionen festgelegt.

Nach oben