wtorek, 12 maja 2015

[PHP][PDO] Podstawy cz.2 - pobieranie rekordów z bazy

TRUE
5389775072567434282
Połączenie z bazą danych opisane zostało w części pierwszej. W tej części za pomocą PDO pobierzemy z bazy kilka rekordów, a w następnych częściach nauczymy się bindować zmienne i parametryzować zapytania, dodawać nowe rekordy i edytować już istniejące. Klasa PDO oferuje ku temu kilka naprawdę ciekawych rozwiązań, z którymi warto się zapoznać. Koncepcja pracy z PDO niejako powinna wymusić na nas zapomnienie o starszych standardach, gdy wszelkie zapytania do bazy wykonywało się za pomoca poleceń rodzaju query(). Tutaj będziemy to robić nieco inaczej i radzę się tego trzymać.

1. Ustawienie parametru - setAttribute()

W poprzednim artykule tryb raportowania błędów ustawiliśmy od razu w startowych parametrach połączenia, tym razem zrobimy to ianczej. Na samym początku pracy za pomocą metody $dbh->setAttribute() ustawimy ową opcję wymuszając na klasie rzucenie wyjątku w razie jakiegokolwiek problemu. Posłuży nam do tego metoda:
[code]$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);[/code]
[code] <?php

$db_config = array(
'host' => 'localhost',
 'port' => '3306',
 'user' => 'root',
 'pass' => 'password',
 'db' => 'myDatabase',
 'db_type' => 'mysql',
 'encoding' => 'utf-8'
);

// próba połączenia
try
{
 $dsn = $db_config['db_type'] .
 ':host=' . $db_config['host'] .
 ';port=' . $db_config['port'] .
 ';encoding=' . $db_config['encoding'] .
 ';dbname=' . $db_config['db'];

 // tworzymy obiekt klasy PDO inicjując tym samym połączenie
 $dbh = new PDO($dsn, $db_config['user'],  $db_config['pass']);

// ustawiamy opcję PDO::ATTR_ERRMODE:
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

 // w przypadku błędu, poniższe się już nie wykona:
 define('DB_CONNECTED', true);
 echo '<h1>Connection success!</h1>';

  // łapiemy ewentualny wyjątek:
} catch(PDOException $e)
{
 die('Unable to connect: ' . $e->getMessage());
}
?>[/code]

2. Wysyłanie zapytania - query()

Wysłanie zapytania do bazy może odbyć się na dwa sposoby. Pierwszym jest standardowa metoda query(), która wysyła do bazy całe zapytanie. Jest to najkrótsza metoda do szybkiego pobrania rekordów. Tą metodę przedstawię jedynie w celu pokazania, że takowa jest. Podczas pracy nie będziemy z niej korzystać. Dlaczego? O tym za chwilę. Na początek pobierzmy kilka rekordów za pomocą zwykłego zapytania. Pobierzemy je za pomocą prostej metody:
[code]$dbh->query($zapytanie)[/code]

Testowa tabela

Na początek naszej zabawy z PDO stwórzmy sobie testową bazę, a w niej tabelę customers.
Tabela może wyglądać tak jak na opisie poniżej - będę używał tej tabeli w dalszych przykładach, więc polecam stworzenie takowej:


Tabela: customers
Nazwa pola Typ Dodatkowe Klucz obcy Opis
customer_id int(11) PRIMARY KEY, AUTO_INCREMENT, NOT NULL ID klienta
login varchar(50) NOT NULL login
password varchar(100) NOT NULL hasło
first_name varchar(50) NOT NULL imię
last_name varchar(50) NOT NULL nazwisko
email varchar(100) NOT NULL email
country varchar(50) NOT NULL kraj
city varchar(50) NOT NULL miasto
postal_code varchar(10) NOT NULL kod pocztowy
address varchar(250) NOT NULL adres
phone varchar(25) NOT NULL telefon
created_at int(11) NOT NULL czas utworzenia rekordu
updated_at int(11) NOT NULL czas aktualizacji rekordu

Załóżmy teraz, że naszym celem jest pobranie z tabeli wszystkich rekordów zawierających informacje o klientach. Korzystając z query() zapytanie wyglądać będzie następująco:
[code] $stmt = $dbh->query('SELECT * FROM customers');[/code]
Metoda $dbh->query() zwraca jako zbiór wyników zapytania obiekt klasy PDOStatement (stąd skrótowa nazwa obiektu - $stmt). Po obiekcie tym możemy się przelecieć jak po zwykłej tablicy:

1) za pomocą pętli foreach:
[code] foreach($stmt as $row)
{
  echo 'id: ' . $row['customer_id']  .
  ', imię:' . $row['first_name']  .
  ', nazwisko:' . $row['last_name'] .
  '<br />';
}[/code]

2) za pomocą pętli while i metody $stmt->fetch():
[code] while($row = $stmt->fetch())
{
  echo 'id: ' . $row['customer_id']  .
  ', imię:' . $row['first_name']  .
  ', nazwisko:' . $row['last_name'] .
  '<br />';
}[/code]
W obu powyższych rozwiązaniach wylistowana zostanie lista wszystkich użytkowników zapisanych w tabeli customers.
Przykład kodu:
[code] <?php
// konfiguracja
$conn_config = array(
'host' => 'localhost',
 'port' => '3306',
 'user' => 'root',
 'pass' => 'password',
 'db' => 'myDatabase',
 'db_type' => 'mysql',
 'encoding' => 'utf-8'
);

// próba połączenia
try
{
 $dsn = $conn_config['db_type'] .
 ':host=' . $conn_config['host'] .
 ';port=' . $conn_config['port'] .
 ';encoding=' . $conn_config['encoding'] .
 ';dbname=' . $conn_config['db'];


 $dbh = new PDO($dsn, $conn_config['user'],  $conn_config['pass']);

  // ustawienie trybu raportowania błędów
 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

 define('DB_CONNECTED', true);
 echo '<h1>Connection success!</h1>';

 // zapytanie do bazy
 $stmt = $dbh->query('SELECT * FROM customers');

 // pobranie/wyświetlenie wyników
 while($row = $stmt->fetch())
 {
  echo 'id: ' . $row['customer_id']  .
  ', imię:' . $row['first_name']  .
  ', nazwisko:' . $row['last_name'] .
  '<br />';

 }
  // łapiemy ewentualny wyjątek:
} catch(PDOException $e)
{
 die('Unable to connect: ' . $e->getMessage());
}[/code]
Wynik:
[code] id: 0, imię: Jan, nazwisko: Kowalski
id: 1, imię: Paweł, nazwisko: Nowak
[...][/code]
I na tym kończymy przygodę z używaniem query(), gdyż od tej chwili będziemy to robić inaczej, za pomocą metody prepare() i execute(), ale o tym za chwilę, ponieważ omówić musimy metodę fetch().

3. Pobieranie wierszy

a) Metoda fetch()

Jak już zapewne zauważyliśmy w kodzie, w PDO do pobrania rekordu służy metoda:
[code]$stmt->fetch()[/code]
Domyślnie pobiera ona wiersz jako tablicę asocjacyjną + index. Pozwala ona jednak na lekkie przekonfigurowanie swojej pracy, np. tak, aby zamiast tablicy zwracała nam obiekty, gdzie każdy wiersz (rekord) to oddzielny obiekt, a kolumny tabeli to jego właściwości.

Ustawienia typu zwracanych przez fetch() danych dokonujemy za pomocą metody:
[code]$stmt->setFetchMode($parametr);[/code]
lub
[code]$dbh->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, $parametr);[/code]

gdzie $parametr może przybrać następujące wartości:
  • PDO::FETCH_ASSOC - zwraca wiersz jako tablicę asocjacyjną, gdzie kluczem są nazwy kolumn
  • PDO::FETCH_NAMED - podobnie jak FETCH_ASSOC, ale w przypadku kilku kolumn o tych samych nazwach zwraca tablicę ze wszystkimi wartosciami
  • PDO::FETCH_NUM  - zwraca wiersz jako tablicę z indeksem numerycznym
  • PDO::FETCH_BOTH - zwraca wiersz jako tablicę z indeksem nazwowym oraz numerycznym (ta opcja jest domyślna)
  • PDO::FETCH_OBJ - zwraca wiersz jako anonimowy objekt ustawiając jego właściwości na wartości kolumn
  • PDO::FETCH_LAZY - połączenie FETCH_BOTH i FETCH_OBJ - tworzy właściwości obiektu nazywając właściwości obiektu jako nazwy kolumn lub za pomocą indeksu numerycznego, tak jak zostają wywołane
  • PDO::FETCH_BOUND - zwraca wartości kolumn do zmiennych ustawionych za pomocą bindValue()
  • PDO::FETCH_CLASS - zwraca wiersz jako instancję zadanej klasy, ustawiajac pola jako wlaściwości obiektu
  • PDO::FETCH_INTO - aktualizuje obiekt zadanej klasy ustawiajac odpowiednie właściwości

Ustawienie danej opcji wpływa na metodę fetch() definiując rodzaj zwracanych przez nią danych od miejsca ustawienia opcji. Domyślnie ustawiona jest opcja FETCH_BOTH, czyli zwracamy tablicę asocjacyjną oraz z indeksem, co za tym idzie, do wiersza możemy dostać się za pomocą:
[code]$row['first_name'][/code]
ale możemy też i poprzez index numeryczny:
[code]$row[3][/code]
W przypadku natomiast obiektu (PDO::FETCH_OBJ):
[code]$row->first_name[/code]

Parametr możemy też podać bezpośrednio jako argument metody fetch():
[code]
 while($row = $stmt->fetch(PDO::FETCH_ASSOC))
 {
  echo 'id: ' . $row['customer_id']  .
  ', imię:' . $row['first_name']  .
  ', nazwisko:' . $row['last_name'] .
  '<br />';
 }
[/code]

b) Metoda fetchAll()

Różnica pomiędzy metodą fetch(), a fetchAll() jest taka, iż o ile metoda fetch() pobiera za jednym razem jedynie jeden wiersz, na który ustawiony jest kursor, to metoda fetchAll() pobiera na raz do tablicy wszystkie wiersze. Przy dużej ilości wierszy może to więc powodować niemałe obciążenie.
Przyładowo, metody fetchAll() użyć możemy tak:
[code]
$result = $stmt->fetchAll();
foreach($result as $row)
 {
  echo 'id: ' . $row['customer_id']  .
  ', imię:' . $row['first_name']  .
  ', nazwisko:' . $row['last_name'] .
  '<br />';
 }
[/code]

c) Metoda fetchColumn()

Metoda fetchColumn() służy do zwrócenia wartości danej kolumny z wiersza. Jako parametr przyjmuje numer kolumny w zwracanym zapytaniu, licząc od 0. Brak podania parametru zwraca pierwszą kolumnę otrzymaną w wyniku zapytania.
Przykład użycia:
[code]
$stmt = $dbh->prepare("SELECT first_name, last_name, email FROM customers");
$stmt->execute();
  echo 'imię: ' . $stmt->fetchColumn(0)  .
  ', nazwisko:' . $stmt->fetchColumn(1) .
  ', email:' . $stmt->fetchColumn(2)  .
  '<br />';
[/code]

4. Wysyłanie zapytania - prepare() i execute()

I w tym miejscu doszliśmy do miejsca, gdzie żegnamy się już całkowicie z metodą query(). Jak widać na powyższym przykładzie użycia metody fetchColumn() nie została tam wykorzystana metoda query(), a metoda prepare(). Na czym polega różnica? Za pomocą:
[code]$stmt = $dbh->prepare($query);[/code]
nie wysyłamy całego zapytania od razu do bazy, a jedynie definiujemy jego szkielet.
Zapytanie takie wykonywane jest dopiero po wywołaniu metody:
[code]$stmt->execute();[/code]
Konstrukcja taka pozwala na kilka ciekawych zabiegów, takich jak parametryzowanie zapytań, które omówimy w następnym artykule, a także sprawia, iż oszczędzamy na czasie połączenia z serwerem bazy. W jaki sposób to działa i jakie jeszcze są z tego korzyści? O tym w następnym artykule. Na chwilę obecną jedynie zapamiętajmy, iż od tej chwili będziemy przygotowywać zapytania JEDYNIE za pomocą prepare(). Zapomnijmy o query().

5. Zwolnienie kursora - closeCursor() 

Teraz bardzo ważna sprawa. Jak już napisałem wartością zwracaną przez zapytanie jest zbiór wyników będący obiektem klasy PDOStatement. Specyfika działania PDO pozwala na jednoczesną pracę jedynie na JEDNYM otwartym zbiorze. Czym jednak jest ten tzw. kursor? Otóż w momencie pobierania wyników ze zbioru, np. w pętli za pomocą metody fetch() - podczas każdego kolejnego przebiegu pętli ustawiany jest wskaźnik, czyli nasz kursor. Wskaźnik ten ustawiany jest na kolejny rekord ze zbioru - dzięki temu mozemy pobierać kolejne rekordy w pętlach. Chcąc więc pracować na kolejnym zbiorze wyników zwróconym przez kolejne zapytanie musimy ten kursor zwolnić i ustawić go z powrotem na pierwszy element z nowego zbioru wyników. Służy do tego metoda:
[code] $stmt->closeCursor():[/code]
którą wywołujemy ZAWSZE po skończonej pracy na danym zbiorze wyników.

Przykład użycia closeCursor():
[code] <?php
// konfiguracja
$conn_config = array(
'host' => 'localhost',
 'port' => '3306',
 'user' => 'root',
 'pass' => 'password',
 'db' => 'myDatabase',
 'db_type' => 'mysql',
 'encoding' => 'utf-8'
);

// próba połączenia
try
{
 $dsn = $conn_config['db_type'] .
 ':host=' . $conn_config['host'] .
 ';port=' . $conn_config['port'] .
 ';encoding=' . $conn_config['encoding'] .
 ';dbname=' . $conn_config['db'];

 $dbh = new PDO($dsn, $conn_config['user'],  $conn_config['pass']);

 // ustawienie trybu raportowania błędów
 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

 define('DB_CONNECTED', true);
 echo '<h1>Connection success!</h1>';

 // zapytanie do bazy
 $stmt = $dbh->prepare('SELECT * FROM customers');
 $stmt->execute();

 // pobranie/wyświetlenie wyników
 while($row = $stmt->fetch())
 {
  echo 'id: ' . $row['customer_id']  .
  ', imię:' . $row['first_name']  .
  ', nazwisko:' . $row['last_name'] .
  '<br />';
 }

 // zwolnienie kursora
 $stmt->closeCursor();
 unset($stmt);

 // [...] dalsze zapytania do bazy możliwe - kursor został zwolniony...

 // zamknięcie połączenia z bazą
 $dbh = null;

// wyłapanie wyjątku w przypadku błędu połączenia z bazą
} catch(PDOException $e)
{
 die('Unable to connect: ' . $e->getMessage());
}
?>[/code]

No i to w zasadzie tyle z podstaw odnośnie pobierania rekordów z bazy. W następnym artykule omówimy sobie tworzenie sparametryzowanych zapytań. Na koniec jeszcze dwie sprawy: jeśli chcemy sobie potestować rodzaje zwracanych przez fetch() danych, możemy sobie to zrobić za pomocą takiego wzoru:

[code]$stmt = $dbh->prepare('SELECT * FROM customers');
$stmt->execute();

echo('PDO::FETCH_ASSOC: ');
echo('Wiersz indeksowany przez nazwę kolumny<br />');
$result = $stmt->fetch(PDO::FETCH_ASSOC);
echo_r($result);
echo(' <br />');

echo('PDO::FETCH_BOTH: ');
echo('Wiersz indeksowany przez nazwę kolumny i indeks numeryczny <br />');
$result = $stmt->fetch(PDO::FETCH_BOTH);
echo_r($result);
echo(' <br />');

echo('PDO::FETCH_LAZY: ');
echo('Wiersz zwracany jako obiekt - nazwy kolumn jako właściwości obiektu lub indeks numerowy <br />');
$result = $stmt->fetch(PDO::FETCH_LAZY);
echo_r($result);
echo(' <br />');

echo('PDO::FETCH_OBJ: ');
echo('Wiersz zwracany jako obiekt - nazwy kolumn jako właściwości obiektu<br />');
$result = $stmt->fetch(PDO::FETCH_OBJ);
echo $result->LOGIN;
echo(' <br />');
[/code]

6. Zwracanie liczby rekordów - COUNT()

Drugą sprawą na koniec jest policzenie rekordów w tabeli.
Zrobimy to w następujący sposób
[code] $stmt = $dbh->prepare('SELECT COUNT(customer_id) FROM customers');
$stmt->execute();
$result = $stmt->fetchColumn();
$stmt->closeCursor();
echo 'Liczba wierszy: ' . $result;[/code]

Oficjalny, pełny manual biblioteki PDO znajduje się tutaj: http://php.net/manual/en/book.pdo.php

5 komentarzy:

  1. Dzięki właśnie tego szukałem! Dobra robota będę na pewno dalej korzystał z twoich poradników! :)

    OdpowiedzUsuń
    Odpowiedzi
    1. Php Majster: [Php][Pdo] Podstawy Cz.2 - Pobieranie Rekordów Z Bazy >>>>> Download Now

      >>>>> Download Full

      Php Majster: [Php][Pdo] Podstawy Cz.2 - Pobieranie Rekordów Z Bazy >>>>> Download LINK

      >>>>> Download Now

      Php Majster: [Php][Pdo] Podstawy Cz.2 - Pobieranie Rekordów Z Bazy >>>>> Download Full

      >>>>> Download LINK 1s

      Usuń
  2. Ja pierdole zajebiscie qwa dzieki

    OdpowiedzUsuń
  3. Co z tym encoding? Czy na pewno może być 'utf-8'? Bo niektóre źródła podają, że musi być 'utf8'...

    OdpowiedzUsuń
  4. Php Majster: [Php][Pdo] Podstawy Cz.2 - Pobieranie Rekordów Z Bazy >>>>> Download Now

    >>>>> Download Full

    Php Majster: [Php][Pdo] Podstawy Cz.2 - Pobieranie Rekordów Z Bazy >>>>> Download LINK

    >>>>> Download Now

    Php Majster: [Php][Pdo] Podstawy Cz.2 - Pobieranie Rekordów Z Bazy >>>>> Download Full

    >>>>> Download LINK

    OdpowiedzUsuń

Masz sugestię? Znalazłeś błąd? Napisz komentarz! :)

webmaester.pl - profesjonalne projektowanie WWW i webaplikacji
webmaester.pl - profesjonalne projektowanie WWW i webaplikacji