Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: PDO w akcji
Forum PHP.pl > Forum > PHP > Object-oriented programming
PawelC
Witam smile.gif
Tworzę sobie klasę do zarządzania użytkownikiem, czyli dodanie, kasowanie, wyświetlenia loginu i póki co hasła, chciałem Was jako bardziej doświadczonych speców, zapytać czy wszystko jest dobrze w kodzie. Proszę również o ocenę podziału, zarządzania użytkownikiem na 2 klasy, z których każda robi co innego.

UserManager.php
  1. <?php
  2. class UserManager{
  3.  
  4. //Database connection
  5. public function __construct()
  6. {
  7. try
  8. {
  9. $this->db = new PDO('mysql: host=localhost; dbname=test', 'root','');
  10. }
  11. catch(PDOException $e)
  12. {
  13. throw new Exception($e->getMessage());
  14. }
  15. }
  16.  
  17. //Create new user
  18. public function create($user, $pass)
  19. {
  20. $result=$this->db->prepare("INSERT INTO users VALUES('',:user,:pass)");
  21. $result->bindParam(':user',$user, PDO::PARAM_STR);
  22. $result->bindParam(':pass',$pass, PDO::PARAM_STR);
  23. if(!$result->execute()){
  24. throw new Exception('Konto nie zostało utworzone!');
  25. }
  26. }
  27.  
  28. //Delete user
  29. public function delete($id)
  30. {
  31. $result=$this->db->prepare("DELETE FROM users WHERE id=:id LIMIT 1");
  32. $result->bindParam(':id',$id, PDO::PARAM_INT);
  33. if(!$result->execute()){
  34. throw new Exception("Wystąpił bląd podczas kasowania użytkownika!");
  35. }
  36. }
  37. }
  38. ?>


User.php

  1. <?php
  2. class User{
  3.  
  4. //Database connection
  5. public function __construct()
  6. {
  7. try
  8. {
  9. $this->db = new PDO('mysql: host=localhost; dbname=test', 'root','');
  10. }
  11. catch(PDOException $e)
  12. {
  13. throw new Exception($e->getMessage());
  14. }
  15. }
  16.  
  17. //Select username
  18. public function getUsername($id)
  19. {
  20. $result=$this->db->prepare("SELECT user FROM users WHERE id=:id limit 1");
  21. $result->bindParam(':id',$id, PDO::PARAM_INT);
  22. if(!$result->execute())
  23. {
  24. throw new Exception("Wystąpił bląd podczas pobierania użytkownika!");
  25. }else{
  26. $wynik=$result->fetch(PDO::FETCH_OBJ);
  27. return $wynik->user;
  28. }
  29. }
  30.  
  31. //Select user password
  32. public function getPassword($id)
  33. {
  34. $result=$this->db->prepare("SELECT pass FROM users WHERE id=:id limit 1");
  35. $result->bindParam(':id',$id, PDO::PARAM_INT);
  36. if(!$result->execute())
  37. {
  38. throw new Exception("Wystąpił bląd podczas pobierania użytkownika!");
  39. }else{
  40. $wynik=$result->fetch(PDO::FETCH_OBJ);
  41. return $wynik->pass;
  42. }
  43. }
  44. }
  45. ?>
yevaud
nie rozumiem dlaczego kazdy "user" samodzielnie laczy sie z baza i ma prywatne polaczenie
oprocz tego nie rozumiem czym sie rozni "manager" od "usera", skoro w obu przypadkach traktujesz te klasy tylko jako interfejs do laczenia sie z baza, a nie np. klasy dla samodzielnych obiektow konkretnych uzytkownikow
PawelC
Z tą bazą akurat tymczasowo, chodzi mi o resztę kodu wink.gif

Co do podziału User i UserManager, sugerowałem się wypowiedzą Crozin-a, z tego postu: http://forum.php.pl/index.php?s=&showt...st&p=880097 chyba, że go źle zrozumiałem.
erix
Ty hasło trzymasz plaintekstem...?
PawelC
md5 smile.gif na główkę nie upadłem, żeby nie kodować go. Tyle, że kodowanie hasła jest poza klasą, i do klasy trafia zakodowane md5
Spawnm
raz dajesz echo raz exception przy try...
new pdo wywal po za klasy.
PawelC
Spawnm echo poprawione smile.gif I teraz pytanie do Was, lepiej jest robić taki podział jak widać u mnie, czy tworzyć jedną klasę, która utworzy, skasuje, wyświetli dane usera itp?
Fifi209
Jak dla mnie obie klasy powinny przyjmować jako parametr uchwyt do pdo - to raz.

Dwa klasa user - powinna w konstruktorze przyjmować id użytkownika jak dla mnie - przynajmniej wygląda, że byłoby lepiej.
getUsername - w obecnym przypadku powinno być raczej getUsernameByID
PawelC
Wymodziłem coś takiego:
  1. <?php
  2. class User{
  3. private $_db;
  4. //Database connection
  5. public function __construct(DB $_db)
  6. {
  7. $this->db=$_db;
  8. }
  9. //Ciąg dalszy klasy User

Klasa DB
  1. <?php
  2.  
  3. class DB
  4. {
  5. public function __construct()
  6. {
  7. try
  8. {
  9. $this->baza = new PDO('mysql: host=localhost; dbname=test', 'root','');
  10. }
  11. catch(PDOException $e)
  12. {
  13. throw new Exception($e->getMessage());
  14. }
  15. }
  16.  
  17. public function prepare($query)
  18. {
  19. return $result=$this->baza->prepare($query);
  20. }
  21. }
  22.  
  23. ?>


I działa dobrze smile.gif
Spawnm
Zainteresuj się frameworkami. Taka dobra rada.
Jak dajesz private/protected to rozpoczynaj nazwę od _ czyli private $_db;
Poczytaj o bindColumn() w pdo.
Jeśli chodzi o pytanie czy dzielić na kilka klas czy posiadać jedną której zadaniem będzie zarządzanie userami,
to już sam musisz zdecydować jak ci wygodniej.
PawelC
Dziękuję za rady smile.gif Co do frameworka, od 2 miesięcy używam ZF, ale chcę poznać OOP w lepszym stopniu niż podstawowy. Czasami tworzę jakiś bardzo mały projekt, gdzie framework nie jest kompletnie potrzebny, dlatego wolę mieć gotowy zestaw klas.

Wiem, że znając bardzo dobrze danego frameworka idzie bardzo szybko napisać aplikację, bo sam się o tym przekonałem.

//Kod poprawiłem
fullrespect
Witam,
troche odkurzę temat...

Przepraszam ze znow będzie pytanie "czy dobrze robie" ale jestem na etapie nauki OOP w PHP.

Moim zamiarem bylo stworzenie klasy która bedzie miala za zadanie skrócenie sobie pisania bloku "try {} catch {}".

Nie wiem czy to co wymodziłem w ogole się nadaje do zastosowania (ogólnie to mi działa tak jak założyłem) ale chcialbym sie dowiedzieć czy nie zrobiłem jakichś rażących błędów.

  1. class DbManager extends PDO
  2. {
  3. private $_dbh;
  4. private $_result;
  5.  
  6.  
  7. public function __construct()
  8. {
  9. try {
  10. $this->_dbh = new PDO('mysql:dbname=rcs_wrs_dev; host=127.0.0.1', 'rcs_tomek', 'zmielonamarchewka',
  11. array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
  12. $this->_dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  13. } catch( PDOException $e ) {
  14. echo( $e->getMessage() );
  15. }
  16. }
  17.  
  18.  
  19. public function fetch($query) {
  20. try {
  21. if ( $_result = $this->_dbh->query($query)->fetch() ) {
  22. return $_result;
  23. } else {
  24. return 0;
  25. }
  26. }
  27. catch (PDOException $e) {
  28. echo( $e->getMessage() );
  29. }
  30. }
  31.  
  32.  
  33. public function fetchAll($query) {
  34. try {
  35. if ( $_result = $this->_dbh->query($query)->fetchAll() ) {
  36. return $_result;
  37. } else {
  38. return 0;
  39. }
  40. } catch (PDOException $e) {
  41. echo( $e->getMessage() );
  42. }
  43. }
  44. }


a używam tego tak:

  1. $wiersz = $db->fetch("SELECT Pressure FROM tasks WHERE task_id=94");
  2.  
  3.  
  4. var_dump($wiersz);
  5.  
  6. // array(2) { ["Pressure"]=> string(4) "1029" [0]=> string(4) "1029" }
  7.  


I wszystko wygląda jakby chciało działać smile.gif a w razie błędu/literówki dostanę komunikat.

Dzieki za wszystkie uwagi.
-=Peter=-
Aby uzyskać podobny efekt wystarczy nie wywoływać poniższej linijki w konstruktorze i usunąć wszystkie instrukcje try catch.

  1. $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


Ten kod, który podałeś jest idiotyczny, wyrzuć go - nie żartuję. Jeśli się uczysz OOP to musisz się nauczyć stosować wyjątki i musisz zrozumieć ich przewagę nad tradycyjną obsługą błędów, która jest stosowana w całej bibliotece standardowej php ze względu na zaszłości historyczne.
fullrespect
OK, rozumiem że powinno używać się wyjątków (z tego co się orientuje to PDO ma swoje wyjątki i dlatego ich używam).
Poczytałem http://pl.wikibooks.org/wiki/PHP/Wyj%C4%85tki i tam piszą tak:
Cytat
Obsługę wyjątków posiada jedynie kilka najnowszych, obiektowych modułów:

Standard PHP Library
Biblioteka PHAR
Biblioteka PDO


Nie rozumiem czemu mam się pozbyć bloku try, catch ? Nawet na php.net jest to stosowane: http://www.php.net/manual/pl/language.exceptions.php


Albo coś pominąłem albo nie mam zielonego pojęcia co ja robię tu smile.gif
-=Peter=-
Usuwając bloki try catch miałem na myśli metody klasy DbManager. Bloki try catch powinny być w kodzie klienta obiektu DbManager. Twój kod jest bardzo zły bo nie mamy kontroli nad tym czy wystąpił błąd. Wywołując poszczególne metody nie wiemy czy nie spowodowała ona błędu. Przykładowo:

  1. $db = new DbManager();
  2. //nie wiemy czy zostało nawiązane poprawne połączenie z bazą danych, czy nie
  3.  
  4. $data = $db->fetch(...);
  5.  
  6. //nie wiemy czy wystąpił błąd, nie wiemy nawet czy $db ma poprawny stan (połączenie z bazą się powiodło)
  7. //rób coś z $data
  8.  
  9. $data = $db->fetchAll(...);
  10.  
  11. //nie wiemy czy wystąpił błąd...
  12. //rób coś z $data


Można poprawić ten kod poprzez zwracanie jakieś określonej wartości w przypadku błędu, zazwyczaj jest to wartość false lub -1 (czasy C oraz php przed pojawieniem się wyjątków wink.gif)

  1. //metody DbManager
  2.  
  3. public function fetch($query) {
  4. if(błąd) {
  5. return false;
  6. } else {
  7. return wynik zapytania;
  8. }
  9. }
  10.  
  11. public function fetchAll($query) {
  12. if(błąd) {
  13. return false;
  14. } else {
  15. return wynik zapytania;
  16. }
  17. }
  18.  
  19. //kod klienta
  20. $db = new DbManager();
  21. //nadal nie wiemy czy połączenie się powiodło
  22.  
  23. $data = $db->fetch(...);
  24.  
  25. if($data === false) {
  26. //obsługa błędu
  27. } else {
  28. //rób coś z danymi
  29. }
  30.  
  31. $data = $db->fetchAll(...);
  32.  
  33. if($data === false) {
  34. //obsługa błędu
  35. } else {
  36. //rób coś z danymi
  37. }


To rozwiązanie już jest odrobinę lepsze, ale minusem jest to że kod obsługi błędów jest wymieszany z kodem prawidłowego przebieg programu, błąd obsługiwać trzeba natychmiast po wywołaniu metody oraz jest pełno instrukcji warunkowych i powtórzeń kodu obsługi błędów.

Ostatnie rozwiązanie to wyjątki, jeśli wystąpił błąd to rzucaj wyjątkiem.

  1. //przechwytuje wyjątki w kliencie obiektu DbManager, a nie w samej klasie DbManager
  2. try {
  3. //w tym bloku nie zawracamy sobie dupy błędamy, bo zakładam że każda metoda wyrzuci wyjątek jeśli wystąpi błąd
  4.  
  5. $db = new DbManager();
  6. $data = $db->fetch(...);
  7. //rób coś z $data
  8. $data = $db->fetchAll(...);
  9. //rób coś z $data
  10. } catch (Exception $e){
  11. //obsługa błędów. Tutaj wskoczymy jeśli którakolwiek z metod wyrzuci wyjątek
  12. }
!*!
Tylko po co te nakładki? Tylko po to, aby kod był "krótki" ? I dane połączenia tworzą się same w konstruktorze?
fullrespect
@-=Peter=-
Dzieki za wskazówki i pięknie przedstawiony kod.

Ale wychodzi na to ze now musze klepac try {} catch {} na kazdym kroku...
A moze polecice jakis artykól o wyjątkach i ich traktowaniu ?
!*!
Cytat(fullrespect @ 20.10.2012, 02:12:55 ) *
A moze polecice jakis artykól o wyjątkach i ich traktowaniu ?

http://pl.wikibooks.org/wiki/PHP/Wyjątki
pamil
Cytat(Spawnm @ 18.07.2011, 21:08:59 ) *
Jak dajesz private/protected to rozpoczynaj nazwę od _ czyli private $_db;

To naleciałość z PHP4, aby oznaczyć daną właściwość jako prywatną, teraz ze względu na modyfikatory dostępu to nie ma sensu.
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.