Najlepszy sposób działania dla Ciebie będzie zależał od tego, jak podchodzisz do dostępu do danych. Można zastosować trzy podejścia:
- Użyj procedur składowanych
- Zachowaj zapytania w kodzie (ale umieść wszystkie swoje zapytania w funkcjach i napraw wszystko, aby używać PDO dla parametrów, jak wspomniano wcześniej)
- Użyj narzędzia ORM
Jeśli chcesz przekazać swój własny surowy SQL do silnika bazy danych, wtedy procedury składowane będą dobrym rozwiązaniem, jeśli wszystko, co chcesz zrobić, to usunąć surowy SQL z kodu PHP, ale pozostawić go względnie niezmienionym. Debata na temat procedur składowanych i surowego SQL jest trochę świętą wojną, ale K. Scott Allen ma doskonałą argumentację – choć jednorazową – w artykule o wersjonowanie baz danych :
Zwykle skłaniam się ku nieużywaniu procedur przechowywanych. Pracowałem nad projektami, w których DB ma API uwidaczniane przez procedury składowane, ale procedury składowane mogą nakładać własne ograniczenia, a te projekty mają wszystkie , w różnym stopniu, używał dynamicznie generowanego surowego kodu SQL w kodzie, aby uzyskać dostęp do bazy danych.
Posiadanie warstwy API w bazie danych daje lepsze rozgraniczenie odpowiedzialności między zespołem DB a zespołem deweloperów kosztem pewnej elastyczności, którą miałbyś, gdyby zapytanie zostało zachowane w kodzie, jednak projekty PHP są mniej prawdopodobne, aby miały duże rozmiary wystarczająco dużo zespołów, aby skorzystać z tego nakreślenia.
Koncepcyjnie prawdopodobnie powinieneś mieć wersjonowaną bazę danych. Praktycznie rzecz biorąc, istnieje większe prawdopodobieństwo, że wersjonujesz tylko swój kod, niż wersjonujesz bazę danych. Prawdopodobnie zmienisz swoje zapytania podczas wprowadzania zmian w kodzie, ale jeśli zmieniasz zapytania w procedurach składowanych przechowywanych w bazie danych, prawdopodobnie nie będziesz ich zaewidencjonować podczas zaewidencjonowania kodu i stracisz wiele korzyści płynących z wersjonowania znacznego obszaru aplikacji.
Niezależnie od tego, czy zdecydujesz się nie używać procedur składowanych, powinieneś przynajmniej upewnić się, że każda operacja bazy danych jest przechowywana w niezależnej funkcji, a nie jest osadzona w każdym ze skryptów Twojej strony - zasadniczo warstwa API dla Twojej bazy danych, która jest utrzymywany i wersjonowany z twoim kodem. Jeśli używasz procedur składowanych, oznacza to, że masz dwie warstwy API dla swojej bazy danych, jedną z kodem, a drugą z bazą danych, co może wydawać się niepotrzebnie komplikować, jeśli Twój projekt nie ma oddzielnych zespołów. Z pewnością tak.
Jeśli chodzi o schludność kodu, to są sposoby na to, aby kod z zaciętym SQL był bardziej czytelny, a pokazana poniżej klasa UserManager jest dobrym sposobem na rozpoczęcie - klasa zawiera tylko zapytania, które odnoszą się do tabeli 'user', każde zapytanie ma swoją własną metodę w klasie, a zapytania są wcięte do instrukcji przygotowania i sformatowane tak, jakbyś sformatował je w procedurze składowanej.
// 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'];
Jeśli jednak twoje zapytania są dość podobne, ale masz ogromną liczbę permutacji w warunkach zapytania, takich jak skomplikowane stronicowanie, sortowanie, filtrowanie itp., prawdopodobnie najlepszym rozwiązaniem jest narzędzie do mapowania obiektów/relacyjności, chociaż proces przeróbki istniejącego kodu korzystanie z tego narzędzia może być dość skomplikowane.
Jeśli zdecydujesz się zbadać narzędzia ORM, powinieneś spojrzeć na Propel , komponent ActiveRecord Yii lub król-tata PHP ORM, Doktryna . Każdy z nich daje możliwość programowego budowania zapytań do bazy danych z użyciem wszelkiego rodzaju skomplikowanej logiki. Doctrine jest najbardziej funkcjonalnym narzędziem, które umożliwia tworzenie szablonu bazy danych za pomocą takich elementów, jak Zestaw zagnieżdżony wzór drzewa po wyjęciu z pudełka.
Pod względem wydajności, procedury składowane są najszybsze, ale generalnie niewiele przewyższają surowy sql. Narzędzia ORM mogą mieć znaczący wpływ na wydajność na wiele sposobów — nieefektywne lub nadmiarowe zapytania, ogromne operacje we/wy plików podczas ładowania bibliotek ORM przy każdym żądaniu, dynamiczne generowanie SQL przy każdym zapytaniu… wszystko to może mieć wpływ, ale użycie narzędzia ORM może drastycznie zwiększyć dostępną moc przy znacznie mniejszej ilości kodu niż tworzenie własnej warstwy DB z ręcznymi zapytaniami.
Gary Richardson jest jednak całkowicie słuszne, jeśli zamierzasz nadal używać SQL w swoim kodzie, zawsze powinieneś używać przygotowanych instrukcji PDO do obsługi parametrów, niezależnie od tego, czy używasz zapytania, czy procedury składowanej. Sanityzacja danych wejściowych jest wykonywana za Ciebie przez 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);
Zastrzeżenie:zakładając, że identyfikator to 1, powyższy skrypt wygeneruje string(1) "1"
. PDO->lastInsertId()
zwraca identyfikator jako ciąg znaków niezależnie od tego, czy aktualna kolumna jest liczbą całkowitą, czy nie. Prawdopodobnie nigdy nie będzie to dla ciebie problemem, ponieważ PHP automatycznie wykonuje rzutowanie łańcuchów na liczby całkowite.
Poniższe zwróci bool(true)
:
// regular equality test
var_dump($lastInsertId == 1);
ale jeśli masz kod, który oczekuje, że wartość będzie liczbą całkowitą, na przykład is_int lub PHP "jest naprawdę, naprawdę, w 100% równy" operator:
var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);
możesz napotkać pewne problemy.
Edytuj: Dobra dyskusja na temat procedur składowanych tutaj