Die beste Vorgehensweise für Sie hängt davon ab, wie Sie Ihren Datenzugriff angehen. Es gibt drei Ansätze, die Sie wählen können:
- Gespeicherte Prozeduren verwenden
- Belassen Sie die Abfragen im Code (aber packen Sie alle Ihre Abfragen in Funktionen und korrigieren Sie alles, um PDO für Parameter zu verwenden, wie zuvor erwähnt)
- Verwenden Sie ein ORM-Tool
Wenn Sie Ihr eigenes Roh-SQL an die Datenbank-Engine übergeben möchten, sind gespeicherte Prozeduren der richtige Weg, wenn Sie lediglich das Roh-SQL aus Ihrem PHP-Code herausholen, aber relativ unverändert lassen möchten. Die Debatte zwischen gespeicherten Prozeduren und rohem SQL ist ein bisschen wie ein heiliger Krieg, aber K. Scott Allen bringt in einem Artikel über Versionierung von Datenbanken :
Ich neige dazu, keine gespeicherten Prozeduren zu verwenden. Ich habe an Projekten gearbeitet, bei denen die DB über eine API verfügt, die durch gespeicherte Prozeduren verfügbar gemacht wird, aber gespeicherte Prozeduren können eigene Einschränkungen auferlegen, und diese Projekte haben alle , in unterschiedlichem Maße, verwendete dynamisch generiertes Roh-SQL im Code, um auf die Datenbank zuzugreifen.
Eine API-Schicht in der DB bietet eine bessere Abgrenzung der Verantwortlichkeiten zwischen dem DB-Team und dem Entwicklerteam auf Kosten der Flexibilität, die Sie hätten, wenn die Abfrage im Code beibehalten würde, aber PHP-Projekte sind wahrscheinlich weniger groß genügend Teams, um von dieser Abgrenzung zu profitieren.
Konzeptionell sollten Sie Ihre Datenbank wahrscheinlich versioniert haben. In der Praxis ist es jedoch viel wahrscheinlicher, dass Sie nur Ihren Code versioniert haben als Ihre Datenbank. Sie ändern wahrscheinlich Ihre Abfragen, wenn Sie Änderungen an Ihrem Code vornehmen, aber wenn Sie die Abfragen in gespeicherten Prozeduren ändern, die in der Datenbank gespeichert sind, werden Sie diese wahrscheinlich nicht einchecken, wenn Sie den Code einchecken, und Sie verlieren viele der Vorteile der Versionierung für einen wichtigen Bereich Ihrer Anwendung.
Unabhängig davon, ob Sie gespeicherte Prozeduren nicht verwenden oder nicht, sollten Sie zumindest sicherstellen, dass jede Datenbankoperation in einer unabhängigen Funktion gespeichert wird und nicht in jedes Skript Ihrer Seite eingebettet ist - im Wesentlichen eine API-Schicht für Ihre Datenbank mit Ihrem Code gepflegt und versioniert wird. Wenn Sie gespeicherte Prozeduren verwenden, bedeutet dies effektiv, dass Sie zwei API-Ebenen für Ihre DB haben, eine mit dem Code und eine mit der DB, was Ihrer Meinung nach die Dinge unnötig verkompliziert, wenn Ihr Projekt keine separaten Teams hat. Das tue ich auf jeden Fall.
Wenn es um die Sauberkeit des Codes geht, gibt es Möglichkeiten, Code mit darin gestautem SQL präsentabler zu machen, und die unten gezeigte UserManager-Klasse ist ein guter Anfang - die Klasse enthält nur Abfragen, die sich auf die Tabelle "Benutzer" beziehen. Jede Abfrage hat ihre eigene Methode in der Klasse und die Abfragen werden in die Prepare-Anweisungen eingerückt und so formatiert, wie Sie sie in einer gespeicherten Prozedur formatieren würden.
// UserManager.php:
class UserManager
{
function getUsers()
{
$pdo = new PDO(...);
$stmt = $pdo->prepare('
SELECT u.userId as id,
u.userName,
g.groupId,
g.groupName
FROM user u
INNER JOIN group g
ON u.groupId = g.groupId
ORDER BY u.userName, g.groupName
');
// iterate over result and prepare return value
}
function getUser($id) {
// db code here
}
}
// index.php:
require_once("UserManager.php");
$um = new UserManager;
$users = $um->getUsers();
foreach ($users as $user) echo $user['name'];
Wenn Ihre Abfragen jedoch ziemlich ähnlich sind, Sie jedoch eine große Anzahl von Permutationen in Ihren Abfragebedingungen wie kompliziertes Paging, Sortieren, Filtern usw. haben, ist ein Object/Relational-Mapper-Tool wahrscheinlich der richtige Weg, obwohl der Prozess der Überarbeitung Ihres vorhandenen Codes die Verwendung des Tools könnte ziemlich kompliziert sein.
Wenn Sie sich entscheiden, ORM-Tools zu untersuchen, sollten Sie sich Propel ansehen , die ActiveRecord-Komponente von Yii , oder das king-daddy PHP ORM, Doctrine . Jede davon gibt Ihnen die Möglichkeit, programmgesteuert Abfragen an Ihre Datenbank mit allerlei komplizierter Logik zu erstellen. Doctrine ist am umfassendsten ausgestattet und ermöglicht es Ihnen, Ihre Datenbank mit Dingen wie dem Nested Set zu erstellen Baummuster sofort einsatzbereit.
In Bezug auf die Leistung sind gespeicherte Prozeduren die schnellsten, aber im Allgemeinen nicht viel mehr als rohes SQL. ORM-Tools können auf verschiedene Weise erhebliche Auswirkungen auf die Leistung haben – ineffiziente oder redundante Abfragen, riesige Datei-E/A beim Laden der ORM-Bibliotheken bei jeder Anfrage, dynamische SQL-Generierung bei jeder Abfrage … all diese Dinge können Auswirkungen haben, aber Die Verwendung eines ORM-Tools kann die Ihnen zur Verfügung stehende Leistung mit einer viel geringeren Codemenge drastisch steigern, als wenn Sie Ihre eigene DB-Schicht mit manuellen Abfragen erstellen.
Gary Richardson ist absolut richtig, wenn Sie weiterhin SQL in Ihrem Code verwenden, sollten Sie immer die vorbereiteten Anweisungen von PDO verwenden, um die Parameter zu behandeln, unabhängig davon, ob Sie eine Abfrage oder eine gespeicherte Prozedur verwenden. Die Bereinigung der Eingaben wird von PDO für Sie durchgeführt.
// optional
$attrs = array(PDO::ATTR_PERSISTENT => true);
// create the PDO object
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", $attrs);
// also optional, but it makes PDO raise exceptions instead of
// PHP errors which are far more useful for debugging
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('INSERT INTO venue(venueName, regionId) VALUES(:venueName, :regionId)');
$stmt->bindValue(":venueName", "test");
$stmt->bindValue(":regionId", 1);
$stmt->execute();
$lastInsertId = $pdo->lastInsertId();
var_dump($lastInsertId);
Achtung:Unter der Annahme, dass die ID 1 ist, gibt das obige Skript string(1) "1"
aus . PDO->lastInsertId()
gibt die ID als String zurück, unabhängig davon, ob die tatsächliche Spalte eine Ganzzahl ist oder nicht. Dies wird wahrscheinlich nie ein Problem für Sie sein, da PHP Strings automatisch in Ganzzahlen umwandelt.
Folgendes wird bool(true)
ausgeben :
// regular equality test
var_dump($lastInsertId == 1);
aber wenn Sie Code haben, der erwartet, dass der Wert eine ganze Zahl ist, wie is_int oder PHPs "ist wirklich, wirklich, 100 % gleich" Betreiber:
var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);
Sie könnten auf einige Probleme stoßen.
Bearbeiten: Einige gute Diskussionen zu gespeicherten Prozeduren hier