Współpraca mysqli z bazą (wariant obiektowy)

Mirosław Zelent

W tym artykule przedstawimy porównanie skryptów łączących się z bazą danych w wariantach proceduralnym i obiektowym, ze szczegółowym omówieniem tej drugiej metody. Za każdym razem najpierw pokażemy wariant proceduralny, po czym nastąpi alternatywny kod obiektowy, wraz z krótkimi wyjaśnieniami. Pamiętajmy, że cały kod skryptu obiektowego znajdziemy w paczce ZIP dołączonej do tego odcinka (katalog "koniec pracy", a w nim plik "index2.php"). Przed nauką podejścia obiektowego w mysqli, warto najpierw dobrze poznać podejście proceduralne. Ponadto, osobom chcącym zrozumieć paradygmat abstrakcyjnego myślenia opartego o klasy, obiekty i metody polecam zobaczenie tego tutoriala. A teraz przejdźmy już do poszczególnych zadań skryptu współpracującego z bazą danych.

Nawiązanie połączenia

Wariant proceduralny (z użyciem funkcji):

require_once "dbconnect.php";
$conn = mysqli_connect($host, $user, $pass, $db);

Wariant obiektowy:

require_once "dbconnect.php";
$conn = new mysqli($host, $user, $pass, $db);

Nasze połączenie $conn to nowy obiekt, tworzony z użyciem operatora new (ang. nowy). Obiekt będzie posiadał tzw. metody (czyli funkcje przewidziane w przepisie klasy, wywoływane na rzecz naszego obiektu) oraz atrybuty (właściwości, zmienne charakteryzujące obiekt). Natomiast zapis prezentowany powyżej nazywamy konstruktorem (gdyż rzeczywiście następuje tu konstrukcja, czyli stworzenie obiektu).

Obsługa polskich znaków

Wariant proceduralny:

mysqli_set_charset($conn, "utf8");

Wariant obiektowy:

$conn->set_charset("utf8");

W wersji obiektowej ustawienie zestawu znaków utf8 realizowane jest z użyciem metody set_charset() wywołanej na rzecz naszego obiektu $conn. Koniecznie zwróćmy uwagę na operator ->, który jest jak to mówimy dwuargumentowy, to znaczy posiada coś po lewej swojej stronie, jak i po prawej. I w przypadku metod obiektowych mysqli, po lewej stronie operatora -> znajdzie się nasz obiekt $conn reprezentujący połączenie z bazą, zaś po prawej stronie znajdzie się odpowiednia metoda (tutaj set_charset(), ustawiająca zestaw znaków utf8). Metoda tym różni się od zwykłej funkcji, iż jej definicja jest częścią klasy, która opisuje obiekt, przez co może zawierać lepsze mechanizmy hermetyzacji (chronienia, ukrywania) danych oraz obsługi błędów.

Wykonanie zapytania SQL

Wariant proceduralny:

$q = "SELECT id, nazwa FROM klasa";
$result = mysqli_query($conn, $q);

Wariant obiektowy:

$q = "SELECT id, nazwa FROM klasa";
$result = $conn->query($q);

W wersji obiektowej nie potrzebujemy dwóch argumentów (identyfikatora połączenia oraz treści zapytania), gdyż metoda query() wywołana jest przecież na rzecz naszego obiektu $conn (stąd wystarczy jedynie treść zapytania, umieszczona w zmiennej $q).

Pobranie ilości zwróconych rekordów

Wariant proceduralny:

$result = $conn-> query($q);
$ile = mysqli_num_rows($result);

Wariant obiektowy:

$result = $conn-> query($q);
$ile = $result->num_rows;

W tym przypadku mamy do czynienia nie z metodą obiektu, tylko z jego atrybutem num_rows (zwróćmy uwagę na brak nawiasów okrągłych właściwych dla funkcji). Liczba rekordów zostaje umieszczczona w atrybucie num_rows (czyli zmiennej przypisanej do obiektu $conn w klasie).

Fetchowanie pojedynczych rekordów

W artykule dotyczącym wariantu proceduralnego bilioteki mysqli, poznaliśmy trzy sposoby fetchowania rekordów do tablicy jednowymiarowej:

  • mysqli_fetch_row() - wyjmowanie liczbowe - ponumeruj (od zera) szufladki tablicy jednowymiarowej;
  • mysqli_fetch_assoc() - wyjmowanie asocjacyjne (czyli skojarzeniowe) - ponazywaj słownie szufladki tablicy jednowymiarowej, nadając im zawsze taką samą nazwę, jaką noszą kolumny w bazie danych;
  • mysqli_fetch_array() - zarówno ponumeruj jak i ponazywaj szufladki tablicy jednowymiarowej (wada: redundancja danych - każda szufladka jest "podwójna", gdyż istnieje zarówno komórka zaindeksowana numerycznie jak i słownie).

Przykład użycia mysqli_fetch_row():

$q = "SELECT id, nazwa FROM klasa";
$result = mysqli_query($conn, $q);
while($row = mysqli_fetch_row($result))
{
echo $row[0]."<br>"; // $row[0] wypisze id klasy
}

W zapisie obiektowym możemy pozbyć się (dla każdej z tych trzech metod) przedrostka mysqli_, a ponadto zamiast zapisania $result jako argumentu funkcji, umieszczamy go po lewej stronie operatora -> (jako obiekt, na rzecz którego wywołujemy metodę fetchującą pojedynczy rekord):

$q = "SELECT id, nazwa FROM klasa";
$result = $conn-> query($q);
while($row = $result->fetch_row())
{
echo $row[0]."<br>"; // $row[0] wypisze id klasy
}

Dodatkowo, poznajmy także czwarty sposób dostępu do pojedynczych rekordów. Będzie to metoda fetch_object(), która umieszcza wyjęty rekord w obiekcie $obj posiadającym atrybuty o takich samych nazwach jak kolumny w bazie:

$q = "SELECT id, nazwa FROM klasa";
$result = $conn-> query($q);
while($obj = $result->fetch_object())
{
echo $obj->id."<br>";
echo $obj->nazwa."<br>";
}

Zamknięcie połączenia z bazą

Brak linii zamykającej połączenie z bazą danych może spowodować utratę punktów na egzaminie - nie zapomnijmy dokonać tego w odpowiednim miejscu kodu, po wszystkich wykonanych bazodanowych czynnościach!

Wariant proceduralny:

mysqli_close($conn);

Wariant obiektowy:

$conn->close();

Jak widzimy, ponownie mamy tu do czynienia z zapisem obiekt->metoda(), który po uprzednim przepracowaniu poprzednich przykładów nie powinien nas już dziwić.

Obsługa wyjątków zachodzących w aplikacji

W skrypcie umieszczonym w pliku "index2.php" dołączonym do paczki z odcinka, zastosowaliśmy dodatkowo instrukcję try..catch zamiast klasycznego podejścia or die(). To tak zwane "łapanie wyjątków" pozwala nam dużo bardziej elastycznie reagować na poszczególne problemy w aplikacji webowej, zamiast po prostu "zabijać" skrypt. Oczywiście w tym odcinku jedynie zarysowaliśmy tę ideę, po więcej informacji na temat użycia try..catch odsyłam do trzeciego epizodu kursu PHP.