1. DBQuery-Objekt
Unser DBQuery-Objekt emuliert nun einfach eine gespeicherte Prozedur – sobald es ausgeführt wird, gibt es eine Ergebnisressource zurück, die gespeichert werden muss, und wenn Sie Funktionen für die Ergebnismenge verwenden möchten (z. B. num_rows() oder fetch_row() ). ), müssen Sie das MySqlDB-Objekt übergeben. Welche Auswirkung hat es also, wenn das DBQuery-Objekt die vom MySqlDB-Objekt implementierten Funktionen implementiert (das für die Verarbeitung der Ergebnisse einer ausgeführten Abfrage konzipiert ist)? Wir verwenden weiterhin den Code aus dem vorherigen Beispiel und gehen davon aus, dass unsere Ergebnisressourcen jetzt von einem DBQuery-Objekt verwaltet werden. Der Quellcode der DBQuery-Klasse ist in Listing 1 dargestellt.
Listing 1. Verwendung der DBQuery-Klasse.
erfordern 'mysql_db.php';
require_once 'query.php';
$db = new MySqlDb;
$db->connect('host', 'username', 'pass');
$db->query('use content_management_system');
$query = new DBQuery($db);
$query->prepare('SELECT fname,sname FROM users WHERE username=:1S AND pword=:2S AND Expire_time<:3I');
versuchen {
if($query->execute("visualad", "apron", time()))->num_rows() == 1) {
echo('Richtige Anmeldeinformationen');
} anders {
echo('Falsche Anmeldeinformationen / Sitzung abgelaufen');
}
} Catch (QueryException $e) {
echo('Fehler beim Ausführen der Abfrage: ' . $e);
}
Was uns am oben modifizierten Code am meisten interessiert, sind die Catch-Anweisung und die Execute-Anweisung.
· Die Execute-Anweisung gibt keine Ergebnisressource mehr zurück, sondern gibt jetzt das DBQuery-Objekt selbst zurück.
· Das DBQuery-Objekt implementiert nun die Funktion num_rows() – die wir bereits von der DB-Schnittstelle kennen.
· Wenn die Abfrageausführung fehlschlägt, wird eine Ausnahme vom Typ QueryException ausgelöst. Bei der Konvertierung in eine Zeichenfolge werden die Details des aufgetretenen Fehlers zurückgegeben.
Dazu müssen Sie einen Proxy verwenden. Tatsächlich verwenden Sie bereits Proxys in unserem DBQuery-Objekt, aber jetzt werden Sie es ausführlicher verwenden, um es eng an das MySqlDB-Objekt zu binden. Das DBQuery-Objekt wurde mit einem Objekt initialisiert, das die DB-Schnittstelle implementiert, und es enthält bereits eine Mitgliedsfunktion „execute“, die die query()-Methode des DB-Objekts aufruft, um die Abfrage auszuführen. Das DBQuery-Objekt selbst fragt die Datenbank nicht wirklich ab, sondern überlässt diese Aufgabe dem DB-Objekt. Dabei handelt es sich um einen Proxy, also einen Prozess, durch den ein Objekt ein bestimmtes Verhalten implementieren kann, indem es Nachrichten an ein anderes Objekt sendet, das dasselbe oder ein ähnliches Verhalten implementiert.
Dazu müssen Sie das DBQuery-Objekt so ändern, dass es alle Funktionen enthält, die auf einer Ergebnisressource des DB-Objekts ausgeführt werden. Sie müssen die gespeicherten Ergebnisse verwenden, wenn Sie eine Abfrage ausführen, um die entsprechende Funktion des DB-Objekts aufzurufen und deren Ergebnisse zurückzugeben. Die folgenden Funktionen werden hinzugefügt:
Listing 2: Erweiterung der DBQuery-Klasse mithilfe von Proxys.
classDBQuery
{
.....
öffentliche Funktion fetch_array()
{
if (! is_resource($this->result)) {
throw new Exception('Abfrage nicht ausgeführt.');
}
return $this->db->fetch_array($this->result);
}
öffentliche Funktion fetch_row()
{
if (! is_resource($this->result)) {
throw new Exception('Abfrage nicht ausgeführt.');
}
return $this->db->fetch_row($this->result);
}
öffentliche Funktion fetch_assoc()
{
if (! is_resource($this->result)) {
throw new Exception('Abfrage nicht ausgeführt.');
}
return $this->db->fetch_assoc($this->result);
}
öffentliche Funktion fetch_object()
{
if (! is_resource($this->result)) {
throw new Exception('Abfrage nicht ausgeführt.');
}
return $this->db->fetch_object($this->result);
}
öffentliche Funktion num_rows()
{
if (! is_resource($this->result)) {
throw new Exception('Abfrage nicht ausgeführt.');
}
return $this->db->num_rows($this->result);
}
}
Die Implementierung jeder Funktion ist recht einfach. Es prüft zunächst, ob die Abfrage ausgeführt wurde, delegiert dann die Aufgabe an das DB-Objekt und gibt seine Ergebnisse zurück, als wäre es das Abfrageobjekt selbst (sogenannte grundlegende Datenbankfunktion).
2. Typhinweis
Damit der Proxy funktioniert, müssen wir sicherstellen, dass die Variable $db des DBQuery-Objekts eine Instanz eines Objekts ist, das die DB-Schnittstelle implementiert. Typhinweise sind eine neue Funktion in PHP 5, mit der Sie Funktionsparameter in Objekte eines bestimmten Typs umwandeln können. Vor PHP 5 bestand die einzige Möglichkeit, sicherzustellen, dass ein Funktionsparameter ein bestimmter Objekttyp war, darin, die in PHP bereitgestellte Typprüffunktion (d. h. is_a()) zu verwenden. Jetzt können Sie einfach einen Objekttyp umwandeln, indem Sie dem Funktionsparameter den Typnamen voranstellen. Sie haben bereits Typhinweise von unserem DBQuery-Objekt gesehen, das sicherstellt, dass ein Objekt, das die DB-Schnittstelle implementiert, an den Objektkonstruktor übergeben wird.
öffentliche Funktion __construct(DB $db)
{
$this->db = $db;
}
Bei der Verwendung von Typhinweisen können Sie nicht nur Objekttypen, sondern auch abstrakte Klassen und Schnittstellen angeben.
3. Ausnahmen auslösen
Möglicherweise haben Sie anhand des obigen Codes bemerkt, dass Sie eine Ausnahme namens QueryException abfangen (wir werden dieses Objekt später implementieren). Eine Ausnahme ähnelt einem Fehler, ist jedoch allgemeiner. Eine Ausnahme lässt sich am besten mit dem Begriff „Notfall“ beschreiben. Obwohl ein Notfall möglicherweise nicht „tödlich“ ist, muss er dennoch behandelt werden. Wenn in PHP eine Ausnahme ausgelöst wird, wird der aktuelle Ausführungsbereich schnell beendet, unabhängig davon, ob es sich um eine Funktion, einen try..catch-Block oder das Skript selbst handelt. Die Ausnahme durchläuft dann den Aufrufstapel und beendet dabei jeden Ausführungsbereich, bis sie entweder in einem try..catch-Block abgefangen wird oder den oberen Rand des Aufrufstapels erreicht und an diesem Punkt einen schwerwiegenden Fehler generiert.
Die Ausnahmebehandlung ist eine weitere neue Funktion in PHP 5. In Verbindung mit OOP kann damit eine gute Kontrolle über die Fehlerbehandlung und -berichterstattung erreicht werden. Ein try..catch-Block ist ein wichtiger Mechanismus zur Behandlung von Ausnahmen. Sobald die Ausnahme abgefangen und behandelt wurde, wird die Skriptausführung ab der nächsten Codezeile fortgesetzt.
Wenn die Abfrage fehlschlägt, müssen Sie Ihre Ausführungsfunktion ändern, um eine Ausnahme auszulösen. Sie werden ein benutzerdefiniertes Ausnahmeobjekt namens QueryException auslösen – das DBQuery-Objekt, das den Fehler verursacht hat, wird daran übergeben.
Listing 3. Löst eine Ausnahme aus.
/**
*Aktuelle Abfrage ausführen
*
* Führen Sie die aktuelle Abfrage aus und ersetzen Sie alle Punkte durch die bereitgestellten Argumente
* .
*
* @parameters: gemischte $queryParams,... Abfrageparameter
* @return: Ressource A – Referenz, die die Ressource beschreibt, auf der die Abfrage ausgeführt wird.
*/
öffentliche Funktion ausführen($queryParams = '')
{
//Zum Beispiel: SELECT * FROM table WHERE name=:1S AND type=:2I AND level=:3N
$args = func_get_args();
if ($this->stored_procedure) {
/*Rufen Sie die Kompilierungsfunktion auf, um die Abfrage zu erhalten*/
$query = call_user_func_array(array($this, 'compile'), $args);
} anders {
/*Eine gespeicherte Prozedur wurde nicht initialisiert und wird daher als Standardabfrage ausgeführt*/
$query = $queryParams;
}
$result = $this->db->query($query);
if (! $result) {
throw new QueryException($this);
}
$this->result = $result;
/* Beachten Sie, dass wir jetzt das Objekt selbst zurückgeben, wodurch wir Mitgliedsfunktionen aus dem Rückgabeergebnis dieser Funktion aufrufen können */
return $this;
}
4. Verwenden Sie die Vererbung, um benutzerdefinierte Ausnahmen auszulösen.
In PHP können Sie jedes Objekt als Ausnahme auslösen. Zunächst sollte die Ausnahme jedoch von der in PHP integrierten Ausnahmeklasse erben. Indem Sie Ihre eigene benutzerdefinierte Ausnahme erstellen, können Sie weitere Informationen zum Fehler protokollieren, einen Eintrag in einer Protokolldatei erstellen oder tun, was immer Sie möchten. Ihre benutzerdefinierte Ausnahme führt Folgendes aus:
· Protokollieren Sie die Fehlermeldung des durch die Abfrage generierten DB-Objekts.
· Geben Sie genaue Details zu der Codezeile an, in der der Abfragefehler aufgetreten ist – indem Sie den Aufrufstapel untersuchen.
· Fehlermeldungen und Abfragetext anzeigen – bei Konvertierung in eine Zeichenfolge.
Um die Fehlermeldung und den Abfragetext zu erhalten, müssen mehrere Änderungen am DBQuery-Objekt vorgenommen werden.
1. Der Klasse muss ein neues geschütztes Attribut – compiledQuery – hinzugefügt werden.
2. Die Funktion „compile()“ aktualisiert die Eigenschaft „compiledQuery“ der Abfrage mit dem Abfragetext.
3. Es sollte eine Funktion hinzugefügt werden, um den kompilierten Abfragetext abzurufen.
4. Es sollte auch eine Funktion hinzugefügt werden – sie ruft das aktuelle DB-Objekt ab, das dem DBQuery-Objekt zugeordnet ist.
Listing 4. Eine Ausnahme auslösen.
classDBQuery
{
/**
*Speichern Sie die kompilierte Version der Abfrage nach dem Aufruf von „compile()“ oder „execute()“*
* @var string $compiledQuery
*/
protected $compiledQuery;
/**
* Gibt die kompilierte Abfrage zurück, ohne sie auszuführen.
* @parameters: gemischte $params,...Abfrageparameter* @return: string – kompilierte Abfrage*/
öffentliche Funktion kompilieren($params='')
{
if (! $this->stored_procedure) {
throw new Exception("Die gespeicherte Prozedur wurde nicht initialisiert.");
}
/*Parameter ersetzen*/
$params = func_get_args(); //Funktionsparameter abrufen $query = preg_replace("/(?compile_callback($params, 1, "2")', $this->query);
return ($this->compiledQuery = $this->add_strings($query)); //Füge den String wieder in die Abfrage ein}
öffentliche Funktion getDB()
{
return $this->db;
}
öffentliche Funktion getCompiledQuery()
{
return $this->compiledQuery;
}
}
Jetzt können Sie die QueryException-Klasse implementieren. Beachten Sie, wie Sie durch die Aufrufliste gehen, um die Stelle im Skript zu finden, die den Fehler tatsächlich verursacht hat. Dies ist genau dann der Fall, wenn das DBQuery-Objekt, das die Ausnahme auslöst, eine Unterklasse ist, die vom DBQuery-Objekt erbt.
Listing 5: QueryException-Klasse.
/**
*Abfrageausnahme
*
*Wenn beim Versuch, eine Abfrage auszuführen, ein Fehler auftritt, wird vom Objekt {@link DBQuery} ein Fehler ausgegeben
*/
Die Klasse QueryException erweitert Exception
{
/**
*Anfragetext*
* @var string $QueryText;
*/
protected $QueryText;
/**
*Fehlernummer/-code aus der Datenbank*
* @var string $ErrorCode
*/
protected $ErrorNumber;
/**
*Fehlermeldung aus der Datenbank*
* @var string $ErrorMessage
*/
protected $ErrorMessage;
/**
*Klassenkonstruktor*
* @Parameter: DBQuery $db, das Abfrageobjekt, das die Ausnahme auslöst */
öffentliche Funktion __construct(DBQuery $query)
{
/*Den Aufrufstapel abrufen*/
$backtrace = $this->GetTrace();
/*Zeile und Datei auf den Speicherort setzen, an dem der Fehler tatsächlich aufgetreten ist*/
if (count($backtrace) > 0) {
$x = 1;
/*Wenn die Abfrageklasse geerbt ist, müssen wir Aufrufe von Unterklassen ignorieren*/
while((! isset($backtrace[$x]['line'])) ||
(isset($backtrace[$x]['class']) && is_subclass_of($backtrace[$x]['class'], 'DBQuery')) ||
(strpos(strtolower(@$backtrace[$x]['function']), 'call_user_func')) !== false ) {
/*Schleifenausführung, solange keine Zeilennummer vorhanden ist oder die aufgerufene Funktion eine Unterklasse der DBQuery-Klasse ist*/
++$x;
/*Wenn wir das Ende des Stapels erreichen, verwenden wir den ersten Aufrufer*/
if (($x) >= count($backtrace)) {
$x = count($backtrace);
brechen;
}
}
/*Wenn die obige Schleife mindestens einmal ausgeführt wird, können wir sie um 1 dekrementieren, um die tatsächliche Codezeile zu finden, die den Fehler verursacht hat*/
if ($x != 1) {
$x -= 1;
}
/*Zuletzt können wir die Datei- und Zeilennummern festlegen, die die SQL-Anweisung widerspiegeln sollen, die den Fehler verursacht hat*/
$this->line = $backtrace[$x]['line'];
$this->file = $backtrace[$x]['file'];
}
$this->QueryText = $query->getCompiledQuery();
$this->ErrorNumber = $query->getDB()->errno();
$this->ErrorMessage = $query->getDB()->error();
/*Rufen Sie den Ausnahmekonstruktor der Superklasse auf*/
parent::__construct('Query Error', 0);
}
/**
*Abfragetext abrufen*
* @return string Abfragetext */
öffentliche Funktion GetQueryText()
{
return $this->QueryText;
}
/**
*Fehlernummer erhalten*
* @return string Fehlernummer */
öffentliche Funktion GetErrorNumber()
{
return $this->ErrorNumber;
}
/**
*habe eine Fehlermeldung erhalten*
* @return string Fehlermeldung */
öffentliche Funktion GetErrorMessage()
{
return $this->ErrorMessage;
}
/**
* Wird aufgerufen, wenn das Objekt in einen String konvertiert wird.
* @return string */
öffentliche Funktion __toString()
{
$output = „Abfragefehler in {$this->file} in Zeile {$this->line}nn“;
$output .= "Abfrage: {$this->QueryText}n";
$output .= "Fehler: {$this->ErrorMessage} ({$this->ErrorNumber})nn"
;
}
}
Jetzt funktioniert der Code, den Sie am Anfang dieses Abschnitts gesehen haben.
5. Fazit
In diesem Artikel haben Sie gesehen, wie der Agent die mit der Abfrage verknüpfte DB-Schnittstelle Operationen für ein bestimmtes Abfrageergebnis zuordnet. DBQuery-Objekte stellen dieselben Funktionen wie fetch_assoc() bereit wie DB-Objekte. Diese funktionieren jedoch alle für eine einzelne Abfrage. Sie haben außerdem gelernt, wie Sie mit benutzerdefinierten Ausnahmen detaillierte Informationen darüber liefern, wann und wo ein Fehler aufgetreten ist, und wie Sie die Fehlerbehandlung besser steuern können.