Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] PDO wprawiające w zakłopotanie
Forum PHP.pl > Forum > Przedszkole
SlimShady
Hej Wam,

od jakiegoś czasu, swoje skrypty opieram o bibliotekę PDO. Bardzo ją lubię, tworzenie przy niej kodu sprawia mi większą przyjemność niż korzystanie z klasycznego mysql_*. Jednak z powodu dość rzadkiego opisu posługiwania się nią, jest wiele kwestii, które budzą u mnie niepewność i zaciekawienie. Wiem, że są takie rzeczy jak manual, osobiście sam jestem wielkim zwolennikiem kopania danego hasła w google, aczkolwiek tym razem nie mogę nakierować się na odpowiednią ścieżkę.

Tak więc, ciekawią mnie 2 rzeczy:
1. Kiedy mam wykorzystać $query->fetchAll(), zamiast normalnego $query->fetch(). Z tego co mój mózg wnioskuję, jeśli chcę przypisać sobie do zmiennej wszystkie wyniki pewnego zapytania, wtedy korzystam z fetchAll i mam do dyspozycji wszelkie pobrane rekordy, w jednym zasobniku - czy na pewno?

2. Do czego jest tryb zwracania wyników PDO::FETCH_OBJ? Wiem o nim tyle, że przedstawienie wyników, odbywa się w postaci anonimowego obiektu, o własnościach nazw pól. Ale w jakiej konkretnie sytuacji może on się okazać przydatny? Oraz, czy zdefiniowanie samego PDO::FETCH_ASSOC lub PDO::FETCH_NUM, zwracającego tablicę indeksowaną asocjacyjnie/numerycznie, jest wydajniejsze/szybsze niż to i to łączne (PDO::FETCH_BOTH)?
I jeśli zapiszę $query->fetchObject() oraz $query->fetch(PDO::FETCH_OBJ) da mi to identyczny efekt?

Pozdrawiam smile.gif
SmokAnalog
Fajne pytania, lubię ludzi, którzy rozkminiają smile.gif
  1. Tak jak zauważyłeś, fetchAll zapisuje wszystkie wyniki do tablicy. Przydaje się to wtedy, kiedy... chcesz wszystkie wyniki w tablicy smile.gif Jak iterujesz wiele rekordów, to raczej rzadko chcesz zapisać wszystko w tablicy, a fetch() oszczędza pamięć jadąc wiersz po wierszu. Przykłady kiedy mógłbyś użyć fetchAll()? Może np. wykonujesz jakieś zapytanie i wyświetlasz dane w kilku miejscach różnie posortowane - zamiast osobnych zapytań do bazy możesz wtedy bawić się tablicą z danymi. Oprócz tego wszelkie wypluwanie danych, np. do formatu JSON - przekazujesz całą tablicę do funkcji formatującej. Przykładów może być bardzo wiele.
  2. To już jest głównie kwestia preferencji. Osobiście wolę pracować z tablicą asocjacyjną niż z obiektem, chociaż odczyt danych odbywa się w dość podobny sposób. W obu możesz odwoływać się do określonego pola po nazwie. Tablicę możesz dodatkowo sortować, a obiektu nie. FETCH_NUM jest prawdopodobnie nieco bardziej wydajne niż FETCH_ASSOC, ale są to różnice kompletnie niewarte świeczki. Ja używam tylko FETCH_ASSOC, bo nie widzę sensu w odwoływaniu się do kolumn po indeksach. FETCH_BOTH tworzy większą tablicę z wynikami - nigdy tego nie używam (choć nie z tego powodu). Co do fetchObject to tak, daje to identyczny efekt jak FETCH_OBJ, co jest wyraźnie zaznaczone w oficjalnej dokumentacji.
SlimShady
jak ja lubię ludzi, którzy mnie rozumieją biggrin.gif

poczułem się w pełni usatysfakcjonowany, jedyne co pozostało mi do szczęścia, to jeszcze jedna.. mała kwestia.. w zasadzie to 2 małe kwestię, które warto tu chyba podpiąć, a jak jest okazja, to chciałbym być jak najbardziej pewny swojej wiedzy.

1. Ten temat spotykany był wiele razy, m.in. zamknięcie wskaźnika zapytania. Według mojego rozumowania, $query->closeCursor(); powinienem umieszczać wszędzie, gdzie zarządzam nie całą liczbą wcześniej pobranych rekordów (np. nie po fetchAll), czy to znaczy, że obejmuję to także polecenia INSERT, UPDATE etc?
2. Czy zapis:
  1. if ($query->rowCount() == 0)

jest najszybszym sposobem sprawdzenia, czy zapytanie z INSERT dodało nowy rekord?
ew. myślałem o takim sposobie:
  1. if (!isset($db->lastInsertId))

ale to chyba jednak, nie jest wcale lepsze rozwiązanie..?
Mackos
Cytat(SmokAnalog @ 7.07.2013, 00:11:47 ) *
lubię ludzi, którzy rozkminiają

Cytat
jak ja lubię ludzi, którzy mnie rozumieją

heart.gif (wybaczcie - nie mogłem się powstrzymać).

A tak co do tematu to chyba lepiej tak:
  1. if ($pdo->execute())
  2. return true;
  3. else
  4. return false;
SmokAnalog
zakochany.gif

Mackos, Twój zapis to PHP-owe masło maślane. Wystarczy:
  1. return $pdo->execute();


Jeśli chcesz po prostu sprawdzić czy rekord dodał się prawidłowo, to rzeczywiście wystarczy:
  1. if($query->execute()) {
  2. // udało się dodać do bazy
  3. }


Jeśli dodatkowo chcesz wiedzieć ile dokładnie dodało się rekordów, to rowCount() jest dobrym pomysłem.

Co do kursora, nie do końca rozumiem pytanie. Dokumentacja szczegółowo wyjaśnia działanie closeCursor() - ja tego nigdy nie używałem, a do tej pory nawet nie znałem. Z tego co zrozumiałem, to to się przydaje tylko wtedy, kiedy chcesz kilkukrotnie przeiterować wyniki zapytania, kiedy nie iterujesz całego zestawu wyników. Czyli np. zapytanie zwraca 10 wierszy, a Ty iterujesz w pierwszej porcji 5, w następnej 7, potem 2 itd. Co więcej, dokumentacja twierdzi, że resetowanie kursora to jest domyślne zachowanie wielu systemów baz danych, czyli w nich execute() samo resetuje kursor. Nie zawracałbym sobie głowy tym closeCursor(). A już na pewno nieprzy INSERT i UPDATE - tych zapytań nawet się nie iteruje, prawda? One się po prostu wykonują.
SlimShady
ale ze mnie nieogarnięta istota.. nie pomyślałem nawet, że zwyczajnie samo wykonanie zwróci mi wartość logiczną, eh dzięki chłopaki tongue.gif

co do closeCursor() - spotkałem się już nie jednokrotnie z zaleceniem jego zastosowania i to nie tylko pod pretekstem "zezwolenia" na kolejne, ale co najciekawsze, natrafiłem również na taką notkę:
"w niektórych przypadkach (driver-specific) zwiększa wydajność", oraz głównie, że polepsza to kompatybilność nad innymi systemami baz danych.

i bądź tu mądry ohno-smiley.gif

ostatecznie - chyba się jednak jego pozbędę wink.gif
jeszcze raz dzięki.
markonix
Może się podepnę bo o ile różnice pomiędzy $query->fetchAll(), a $query->fetch() dobrze rozumiem to zastanawiam się nad tym, co powinny zwracać w zaawansowanej aplikacji (np. jakiś framework) metody (funkcje) typu getCośTam. Np. funkcja getUsers - czyli metoda modelu użytkowników zwracająca listę użytkowników.
No i teraz pytanie - zawsze zwracam tablicę obiektów bo wydaje mi się to wygodne i logiczne ale nie jest to optymalne właśnie porównując do iteracji po wierszach.

Jak to rozwiązujecie? Optymalność vs logika, wygoda?
ber32
Witam.
Cytat
ostatecznie - chyba się jednak jego pozbędę

Już ci mogę powiedzieć że będzie to wielki błąd. Poczytaj jeszcze raz gdzie się tego używa. Sprawdź także na większej ilości zapytań select i będziesz wiedział że faktycznie to błąd.

W niektórych przypadkach jest to niezbędne.
SlimShady
Bardzo dziękuje za wypowiedzenie się, teraz mam takie dziwne odczucie i nie wiem, gdzie powinienem je umieścić w następującym kodzie:
  1. //przygotowujemy zapytanie, które ma sprawdzić istnienie już takiego konta
  2. $check = $db->prepare("SELECT id FROM star_users WHERE user = :login OR mail = :mail");
  3. //przefiltrowujemy wpisane dane
  4. $check->bindValue(':login', $_POST['user'], PDO::PARAM_STR);
  5. $check->bindValue(':mail', $_POST['mail'], PDO::PARAM_STR);
  6.  
  7. //wykonujemy zapytanie i sprawdzamy rezultat
  8. if ($check->execute()) echo 'Takie konto już istnieje..';
  9. else {
  10. //jakieś operacje
  11. header('Location: przekierowanie');
  12. }
  13.  
  14. questionmark.gif


W którym miejscu w powyższym kodzie, mogę 'zaaranżować' closeCursor()? Myślałem o przestrzeni nazwanej questionmark.gif, jednak nie wiem, czy wówczas PHP uwzględni je z przekierowaniem i czy będzie to tam potrzebne, oraz ogólnie rzecz mówiąc, jak to przyzwoicie zorganizować, by miało ręce i nogi?
ber32
Widzę, że lektury nie odrobiłeś. Tu przykład z manuala skopiowany, żebyś nie musiał ciężko szukać w taki upał oneeyedsmiley02.png
  1. <?php
  2. /* Create a PDOStatement object */
  3. $stmt = $dbh->prepare('SELECT foo FROM bar');
  4.  
  5. /* Create a second PDOStatement object */
  6. $otherStmt = $dbh->prepare('SELECT foobaz FROM foobar');
  7.  
  8. /* Execute the first statement */
  9. $stmt->execute();
  10.  
  11. /* Fetch only the first row from the results */
  12. $stmt->fetch();
  13.  
  14. /* The following call to closeCursor() may be required by some drivers */
  15. $stmt->closeCursor();
  16.  
  17. /* Now we can execute the second statement */
  18. $otherStmt->execute();

teraz już chyba wiesz, kiedy go stosować ?
SlimShady
u lala, dziękuje biggrin.gif i naprawdę tylko wtedy mam go stosować? - głupie pytanie tongue.gif
ber32
Nie
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.