De beste manier van handelen voor u hangt af van hoe u uw gegevenstoegang benadert. Er zijn drie benaderingen die u kunt volgen:
- Gebruik opgeslagen procedures
- Bewaar de zoekopdrachten in de code (maar zet al je zoekopdrachten in functies en herstel alles om PDO te gebruiken voor parameters, zoals eerder vermeld)
- Gebruik een ORM-tool
Als u uw eigen onbewerkte SQL aan de database-engine wilt doorgeven, zijn opgeslagen procedures de beste keuze als u alleen de onbewerkte SQL uit uw PHP-code wilt halen, maar deze relatief ongewijzigd wilt houden. Het debat over opgeslagen procedures versus onbewerkte SQL is een beetje een heilige oorlog, maar K. Scott Allen maakt een uitstekend punt - zij het een wegwerpartikel - in een artikel over versiedatabases :
Ik neig ernaar om geen opgeslagen procedures te gebruiken. Ik heb aan projecten gewerkt waarbij de DB een API heeft die beschikbaar is via opgeslagen procedures, maar opgeslagen procedures kunnen hun eigen beperkingen opleggen, en die projecten hebben alle , in verschillende mate, gebruikte dynamisch gegenereerde onbewerkte SQL in code om toegang te krijgen tot de DB.
Het hebben van een API-laag op de DB geeft een betere afbakening van de verantwoordelijkheden tussen het DB-team en het Dev-team, ten koste van een deel van de flexibiliteit die u zou hebben als de query in de code zou worden gehouden, maar het is minder waarschijnlijk dat PHP-projecten aanzienlijke genoeg teams om van deze afbakening te profiteren.
Conceptueel zou u waarschijnlijk uw database moeten hebben geversied. In de praktijk is de kans echter veel groter dat alleen uw code wordt geversied dan uw database. U zult waarschijnlijk uw query's wijzigen wanneer u wijzigingen aanbrengt in uw code, maar als u de query's wijzigt in opgeslagen procedures die zijn opgeslagen in de database, zult u deze waarschijnlijk niet inchecken wanneer u de code incheckt en u verliest veel van de voordelen van versiebeheer voor een aanzienlijk deel van uw toepassing.
Ongeacht of u ervoor kiest om geen opgeslagen procedures te gebruiken, u moet er op zijn minst voor zorgen dat elke databasebewerking wordt opgeslagen in een onafhankelijke functie in plaats van te worden ingebed in elk van de scripts van uw pagina - in wezen een API-laag voor uw DB die wordt onderhouden en geversied met uw code. Als u opgeslagen procedures gebruikt, betekent dit in feite dat u twee API-lagen voor uw DB hebt, een met de code en een met de DB, wat volgens u de zaken onnodig ingewikkeld maakt als uw project geen afzonderlijke teams heeft. Dat doe ik zeker.
Als het probleem er een is van de netheid van de code, zijn er manieren om code met SQL erin meer presentabel te maken, en de hieronder getoonde UserManager-klasse is een goede manier om te beginnen - de klasse bevat alleen query's die betrekking hebben op de 'gebruiker'-tabel, elke query heeft zijn eigen methode in de klasse en de query's worden ingesprongen in de voorbereidingsinstructies en opgemaakt zoals u ze zou opmaken in een opgeslagen procedure.
// 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'];
Als uw query's echter veel op elkaar lijken, maar u een groot aantal permutaties heeft in uw queryvoorwaarden, zoals gecompliceerde paging, sortering, filtering, enz., is een Object/Relational mapper-tool waarschijnlijk de juiste keuze, hoewel het proces van het reviseren van uw bestaande code het gebruik van de tool kan behoorlijk ingewikkeld zijn.
Als je besluit om ORM-tools te onderzoeken, moet je kijken naar Propel , de ActiveRecord-component van Yii , of de koning-daddy PHP ORM, Doctrine . Elk van deze geeft u de mogelijkheid om programmatisch query's naar uw database te bouwen met allerlei gecompliceerde logica. Doctrine is de meest volledige functionaliteit, waardoor u uw database kunt sjablonen met zaken als de geneste set boompatroon uit de doos.
In termen van prestaties zijn opgeslagen procedures het snelst, maar over het algemeen niet veel meer dan onbewerkte sql. ORM-tools kunnen op een aantal manieren een aanzienlijke prestatie-impact hebben - inefficiënte of redundante query's, enorme bestands-IO terwijl de ORM-bibliotheken bij elk verzoek worden geladen, dynamische SQL-generatie bij elke query ... al deze dingen kunnen een impact hebben, maar het gebruik van een ORM-tool kan de beschikbare kracht voor u drastisch vergroten met een veel kleinere hoeveelheid code dan het maken van uw eigen DB-laag met handmatige query's.
Gary Richardson heeft echter volkomen gelijk, als je SQL in je code blijft gebruiken, moet je altijd de voorbereide instructies van PDO gebruiken om de parameters af te handelen, ongeacht of je een query of een opgeslagen procedure gebruikt. De ontsmetting van de invoer wordt voor u uitgevoerd door PDO.
// 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);
Waarschuwing:ervan uitgaande dat de ID 1 is, zal het bovenstaande script string(1) "1"
. uitvoeren . PDO->lastInsertId()
retourneert de ID als een tekenreeks, ongeacht of de werkelijke kolom een geheel getal is of niet. Dit zal waarschijnlijk nooit een probleem voor je zijn, aangezien PHP het casten van strings naar gehele getallen automatisch uitvoert.
Het volgende geeft bool(true)
. weer :
// regular equality test
var_dump($lastInsertId == 1);
maar als je code hebt die verwacht dat de waarde een geheel getal is, zoals is_int of PHP's "is echt, echt, 100% gelijk aan" operator:
var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);
u kunt tegen problemen aanlopen.
Bewerken: Een goede discussie over opgeslagen procedures hier