Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [php] OOP - zasięg obiektów
Forum PHP.pl > Forum > Przedszkole
hunter1988
Klasa 1
  1. class Database{
  2. private static $datasource='mysql:host=localhost;dbname=X';
  3. private static $username='X';
  4. private static $password='X';
  5. private static $db;
  6.  
  7.  
  8. private function __construct(){}
  9.  
  10. public static function getDB(){
  11. if(!isset(self::$db)){
  12. try{
  13. self::$db=new PDO(self::$datasource,self::$username,self::$password);
  14.  
  15. }
  16. catch(PDOExceptin $e)
  17. {
  18. $error=$e->getMessage();
  19. exit();
  20. }
  21. }
  22. return self::$db;
  23. }
  24.  
  25. }
  26.  
  27.  


Klasa 2
  1. class weryfikacja
  2. {
  3.  
  4. public function checkEmpty($var, $info)
  5. {
  6. if(strlen($var)==0)
  7. {
  8. echo $info;
  9. return false;
  10. }
  11. else
  12. return true;
  13. }
  14. }


Klasa 3

  1.  
  2. class Uzytkownik
  3. {
  4. public $login;
  5. public $haslo;
  6. public $haslo1;
  7. public $email;
  8.  
  9. public function __construct()
  10. {
  11. $this->pdo = Database::getDB();
  12.  
  13. }
  14.  
  15. public function soilHaslo()
  16. {
  17. $this->haslo = md5($this->haslo);
  18. return $this->haslo;
  19. }
  20.  
  21. public function zrobKod()
  22. {
  23. $kod = uniqid(rand());
  24. return $kod;
  25. }
  26. public function test()
  27. {
  28. $weryfikacja = new weryfikacja;
  29. $weryfikacja->checkEmpty('sdadasda','adsasdas');
  30. }
  31.  
  32. public function addUser()
  33. {
  34.  
  35. // zapytanie do bazy sql
  36. }
  37. }
  38.  


Klasa 1 jest odpowiedzialna za połączenie się z bazą danych
Klasa 2 w domyśle weryfikuje dane wprowadzone przez użytkownika,
Klasa 3 wprowadza operacje na danych, tworzy hasło, unikatowy kod do weryfikacji przez email, dodawanie użytkownika do bazy, edycje itp

Mam problem ze zrozumieniem zasięgu zmiennych, metod, obiektów itp. Wiem, co znaczy private, public, protected ale ciężko jest mi ogarnąć to w praktyce, pisze to w przedszkolu gdyż bardzo krótko programuję a jeszcze krócej w PHP, nie chce być tu karcony przez stwierdzenia typu zrób jakiś kurs albo poczytaj książkę, gdyż do takich rozwiązań już sięgałem, rozumiem iż metodą prób i błędów człowiek uczy się najwięcej ale czy ktoś mógłby mi wytłumaczyć jak działa się i jak powinno działać się....

Klasa 1 łączy z bazą, gdy w Klasie 3 chce coś dodać do bazy to w konstruktorze wywołuję połączenie $this->pdo = Database::getDB();
Podobnie chciałbym w metodzie test() użyć metody z Klasy 2, jak powinienem to zrobić ? Powyższy kod działa poprawnie, ale moje pytanie jest takie czy muszę za każdym razem w metodzie tworzyć nowy obiekt danej klasy jeżeli chcę metodę wykorzystać z innej klasy? Da się tworzyć jakoś obiekt w konstruktorze?

Zaznaczę, że połączenie z funkcją statyczną w klasie 1 w klasie 3 jest wykonane poprawnie, podczas gdy nie mam możliwości tworzenia obiektów klasy 2 w konstruktorze klasy 3
pmir13
Metody statyczne właśnie po to są, by wywoływać je bez potrzeby tworzenia obiektów danej klasy.

  1. class Weryfikacja
  2. {
  3. public static function checkEmpty( $var, $info )
  4. {
  5. ...
  6. }
  7. }
  8.  
  9. ...
  10.  
  11. $v = "test";
  12. if( Weryfikacja::checkEmpty( $v, "pusto tutaj" ) )
  13. echo "wcale nie jest pusto";
Sephirus
Ok przede wszystkim nie uczmy złych praktyk smile.gif

Metody/własności statyczne są wygodne owszem ale przy większym projekcie i jego zarządzaniu okazują się zbyt mało "organizowalne" - zbyt prosto się do nich odwołać (są też mniej wydajne) przez co powstają złe nawyki.

Najpierw co do samego zasięgu.
- public - oznacza, że dana metoda/własność jest widoczna poza ciałem klasy - są to naogół metody i własności główne (te najważniejsze) danej klasy. Ich liczbę powinno się ograniczyć maksymalnie do liczby czynności jakie dana klasa ma realizować. W zasadzie poprzez HERMETYZACJE (zobacz sobie co to jest w OP) nie powinno się stosować publicznych własności klasy - powinny być do nich tzw. gettery i settery - po co to wszystko - poczytaj o tym - zrozumiesz ile to daje wink.gif

- private - to metody i własności, które nie muszą być dostępne na zewnątrz jakiejś klasy. Są one używane wewnątrz. Nieraz tworząc jakąś klasę wykonującą dużo czynności zajmuje ona dużo kodu - aby nie umieszczać go w jednej metodzie można go funkcjonalnie rozdzielić na metody prywatne, wykorzystywane w głównych metodach publicznych klasy.

- protected - to to samo co private lecz pozwala na dziedziczenie. Możesz zrobić sobie klasę z zestawem metod chronionych (protected) i potem kolejną klasę dziedziczącą z tej właśnie. Dzięki temu możesz utworzyć kilka różnych klas dziedziczących po tej jednej, która ma metody wykrozystywane we wszystkich.

To wszystko co napisałem można zastąpić metodami i własnościami statycznymi - nawet wydaje się to łatwiejsze. Niestety tak się robić nie powinno - gubi się wówczas ładną, poukładaną i logiczną strukturę aplikacji - nie mówiąc o wydajności (odwołania statyczne są sporo wolniejsze od dynamicznych).

Masz 3 klasy.
1sza jest ok - połączenie z DB - tu nie mam zastrzeżeń.
2ga i 3cia wymaga zastanowienia. Czy jest to klasa, która będzie używana w wielu miejscach? Czy będzie miała więcej metod walidacyjnych?

Jeśli tak to zrób inaczej i nie twórz w klasie 3ciej instancji 2giej. Niech klasa 3cia dziedziczy po 2giej. Wówczas masz od razu gotową metodę, którą możesz wywołać lokalnie bez powoływania obiektu klasy drugiej.

Nie podpowiadam więcej - przemyśl to wink.gif
hunter1988
Czytałem już wcześniej o __set i __get i na pewno będę chciał tak pisać, ale puki co jak sam widzisz mam takie "życiowe" problemy z oop że nie chcę dokładać do pieca. Wcześniej już robiłem aby klasa uzytkownik była dzieckiem weryfikacja ale nie wiem czemu nie działało mi, widocznie miałem jeszcze coś więcej pokićkane, w tym układzie jak jest teraz sprawdza się to i nie muszę tworzyć nowego obiektu klasy weryfikacja tylko odwołuje się od razu $this-> do danej metody.
Twoje pytanie odnośnie czy to coś więcej będzie robiło, to stwierdziłem że zrobię klasę weryfikacja bo przyda się przy rejestrowaniu, zmianie hasła, maila, może użyje przy dodawaniu czegoś przez użytkownika jakiś wpisów do sprawdzania, w tej klasie chciałem umieścić metody do sprawdzania danych wprowadzanych przez użytkownika. Co do klasy uzytkownik, to po prostu chciałem zrobić prostą rejestrację i tworząc klasę zacząłem zastanawiać się nad tym dlaczego nie mogę użyć danej metody (skoro jest public) i czy wszędzie muszę tworzyć obiekt.

Jeszcze jedno pytanie:
Jak powinno się pisać klasy do obsługi bazy danych, w sensie, jeżeli mam portal to są klasy odpowiedzialne za różne rzeczy, to tworzę JEDNĄ klasę która np dodaje do bazy i edytuje w niej wpisy itp?
Wiem, że można to robić na wiele sposobów ale chodzi mi o dobrą praktykę.
Sephirus
settery i gettery to nie magiczne metody __set i __get - tu trochę mylisz pojęcia. Chodzi o zapis typu:

  1. class Klasa {
  2. private $zmienna = 0;
  3.  
  4. public function getZmienna() {
  5. return $this->zmienna;
  6. }
  7.  
  8. public function setZmienna($zmienna) {
  9. $this->zmienna = $zmienna;
  10. }
  11.  
  12. }


Te metody, które wymieniłeś służą do czegoś innego - do obsługi odwołań do nieistniejących własności obiektu. Przeczytaj coś o hermetyzacji - to Ci dokładnie wytłumaczy jak i po co to stosować.

Co do układu klas to jest ok - jeśli będziesz używał tej "weryfikacji" w wielu miejscach to dziedziczenie będzie chyba najlepszym pomysłem właśnie.

Co do pytania to odpowiedź jest prosta: MODELE

Ogolnie aplikacje (kod) można podzielić na 3 oddzielne części wg architektury zwanej MVC - na początek może nie zaglębiaj się w nią bo ciężko ją na początku zrozumieć. W skrócie chodzi o to by rozdzielić zarządzanie danymi od zarządzania żądaniami (przekazywanie parametrów pod podany adres, wybór odpowiedniej strony itp.) i od warstwy prezentacji. Dzieli się to na kontroler, model i widok (Model-View-Controller). Weź sobie z tego model.

Model to klasa dotycząca (najczęściej) jakieś tabeli w bazie danych. Przykładowo masz tabele z użytkownikami (powiedzmy users). Tworzysz więc klasę modelu "users" albo "usersModel". W tej klasie implementujesz metody, które robią coś z użytkownikami - dodają, zapisują po edycji, kasują, pobierają z DB. W innej klasie (modelu) możesz obsługiwać inne tabele. Cel tutaj jest taki aby tabela miała swój odpowiednik w kodzie w formie klasy.

Robiąc później klasę rejestracji nie implementujesz w niej zapytań SQL itp. a odwołujesz się do konkretnych metod konkretnych modeli. Możesz więc zrobić metodę rejestracja, w niej walidować dane a potem przekazać je do odpowiedniej metody (np.: "dodajUzytkownika(...)") modelu "users".

Sam dostęp do bazy TY oparłeś na PDO i wzbogaciłeś to o klasę, ktora jest globalnie dostępna (poprzez odwołanie statyczne aby nie tworzyć wielu połączeń) i to tak może zostać. Tą klasę używaj w modelach.

Z modelami wiąże się pewien problem - co zrobić a raczej, do którego modelu dodać metodę zwracającą jakieś łączne dane z wielu tabel bądź pracującej na wielu tabelach naraz. To jest kwestia indywidualna. Ogólnie są dwie ścieżki:

1. Metoda zostaje wrzucona do modelu po tym co zwraca. Oznacza to, że jeśli metoda pobiera na przykład produkty klienta to wrzucasz ją do modelu produktów bo ich listę będzie zwracać.

2. Metoda zostaje wrzucona do modelu po tym co przyjmuje. To z kolei oznacza, że metoda trafi do tego modelu, którego dotyczą dane (argumenty) wejściowe tej metody. Czyli jeśli pobieramy produkty klienta to podajemy w metodzie o jakiego klienta nam chodzi - więc metoda ta powinna trafić do modelu klientów.

Oba podejścia są dobre i najczęściej występują mieszanie. Staraj się jednak trzymać jednej - osobiście polecam 2gą - jest bardziej intuicyjna. Tak to wygląda w kodzie:

  1. $produkty = $modelProduktow->pobierzProdukty($idKlienta); // 1
  2.  
  3. $produkty = $modelKlienta->pobierzProdukty($idKlienta); // 2


Wybór należy do Ciebie - co dla Ciebie jest bardziej intuicyjne to wybierz smile.gif

hunter1988
Dobry człowieku, Ty to masz do mnie cierpliwość (nie to żebym się żalił) smile.gif

Z tego co napisałeś zrozumiałem tyle:

  1.  
  2.  
  3. class users extends weryfikacja
  4. {
  5.  
  6. private $login;
  7. private $haslo;
  8. private $email;
  9.  
  10. public function __construct($varlogin, $varhaslo, $varemail)
  11. {
  12.  
  13. $this->pdo = Database::getDB();
  14. $this->login = $varlogin;
  15. $this->haslo = $varhaslo;
  16. $this->email = $varemail;
  17. }
  18.  
  19.  
  20. public function addUser()
  21. {
  22.  
  23. $data_rejestracji = time();
  24. if($this->checkMail($this->email,'') && $this->checkEmpty($this->login,'') &&
  25. $this->checkEmpty($this->haslo,'') && $this->checkLogin($this->login,''))
  26. {
  27. $stmt = $this->pdo -> prepare('INSERT INTO `users` (`login`,`haslo`,`mail`,`kod`,`data_rejestracji`) VALUES(
  28. :login,
  29. :haslo,
  30. :mail,
  31. :kod,
  32. :data_rejestracji)');
  33. $stmt -> bindValue(':login', $this->login, PDO::PARAM_STR);
  34. $stmt -> bindValue(':haslo', $this->haslo, PDO::PARAM_STR);
  35. $stmt -> bindValue(':mail', $this->email, PDO::PARAM_STR);
  36. $stmt -> bindValue(':kod', $this->zrobKod(), PDO::PARAM_STR);
  37. $stmt -> bindValue(':data_rejestracji', $data_rejestracji, PDO::PARAM_STR);
  38. $stmt -> execute();
  39.  
  40.  
  41. }
  42. else
  43. echo "Wprowadzone dane nie są poprawne";
  44. }
  45. public function changePass($new_pass)
  46. {
  47. // i inne funkcje związane tylko z tabelą w bazie users
  48. }
  49.  
  50.  
  51. }
  52.  


Czy można robić to jako w konstruktorze? Wymusza to podawanie 3 wartości przy tworzeniu nowego obiektu. Czy lepiej napisać specjalną metodę na settowanie, która będzie wywoływana w addUser ?
Sephirus
Może być tak (prawie) - co prawda myślałem nad tym by model nie walidował danych ale może w sumie. Ja to ogólnie widzę bardziej tak:

  1. class users extends weryfikacja
  2. {
  3. public function __construct()
  4. {
  5. $this->pdo = Database::getDB(); // rozumiem że $this->pdo jest dziedziczone po "weryfikacja"
  6. // jeśli tak - to może od razu tam w konstuktorze dać $this->pdo = (...)
  7. // wtedy tu konstruktor byłby niepotrzebny ;)
  8. }
  9.  
  10. public function addUser($login,$haslo,$email) // tutaj do konkretnej metody podawaj argumenty - bo konstruktor to kiepski pomysł :)
  11. {
  12.  
  13. $data_rejestracji = time();
  14. if($this->checkMail($this->email,'') && $this->checkEmpty($this->login,'') &&
  15. $this->checkEmpty($this->haslo,'') && $this->checkLogin($this->login,''))
  16. {
  17. $stmt = $this->pdo -> prepare('INSERT INTO `users` (`login`,`haslo`,`mail`,`kod`,`data_rejestracji`) VALUES(
  18. :login,
  19. :haslo,
  20. :mail,
  21. :kod,
  22. :data_rejestracji)');
  23. $stmt -> bindValue(':login', $login, PDO::PARAM_STR);
  24. $stmt -> bindValue(':haslo', $haslo, PDO::PARAM_STR);
  25. $stmt -> bindValue(':mail', $email, PDO::PARAM_STR);
  26. $stmt -> bindValue(':kod', $this->zrobKod(), PDO::PARAM_STR);
  27. $stmt -> bindValue(':data_rejestracji', $data_rejestracji, PDO::PARAM_STR);
  28. $stmt -> execute();
  29.  
  30. }
  31. else
  32. echo "Wprowadzone dane nie są poprawne";
  33. }
  34. public function changePass($new_pass)
  35. {
  36. // i inne funkcje związane tylko z tabelą w bazie users
  37. }
  38. }


Tak jak Ci napisałem najlepiej nic nie kombinować i podać dane metodzie których potrzebuje smile.gif

hunter1988
I już więcej nie męczę, dla upewnienia.

  1. class Model
  2. {
  3. public function __construct()
  4. {
  5. $this->pdo = Database::getDB();
  6. }
  7. }
  8.  
  9.  
  10.  
  11. class Users extends Model
  12. {
  13.  
  14. public function addUser($login, $haslo, $email)
  15. {
  16. $weryfikacja = new Weryfikacja;
  17. $data_rejestracji = time();
  18. if
  19. ($weryfikacja->checkMail($email,'') && $weryfikacja->checkEmpty($login,'') &&
  20. $weryfikacja->checkEmpty($haslo,'') && $weryfikacja->checkLogin($login,''))
  21. {
  22. $stmt = $this->pdo -> prepare('INSERT INTO `users` (`login`,`haslo`,`mail`,`kod`,`data_rejestracji`) VALUES(
  23. :login,
  24. :haslo,
  25. :mail,
  26. :kod,
  27. :data_rejestracji)');
  28. $stmt -> bindValue(':login', $login, PDO::PARAM_STR);
  29. $stmt -> bindValue(':haslo', $haslo, PDO::PARAM_STR);
  30. $stmt -> bindValue(':mail', $email, PDO::PARAM_STR);
  31. $stmt -> bindValue(':kod', $weryfikacja->zrobKod(), PDO::PARAM_STR);
  32. $stmt -> bindValue(':data_rejestracji', $data_rejestracji, PDO::PARAM_STR);
  33. $stmt -> execute();
  34.  
  35.  
  36. }
  37. else
  38. echo "Wprowadzone dane nie są poprawne";
  39. }
  40.  
  41.  
  42. }
  43.  
Szymciosek
Wygląda ok, co prawda w PDO jeszcze inaczej można przekazywać wartości, ale nie o tym.

Staraj się nie mieszać angielskiego z polskim.

$weryfikacja = new Weryfikacja;
$data_rejestracji = time();

tu masz w pełni po polsku, a tutaj już:
$weryfikacja->checkMail(...)

pomieszane trochę, co nie wygląda na dobre.
hunter1988
Cytat(Szymciosek @ 3.06.2013, 13:23:39 ) *
Wygląda ok, co prawda w PDO jeszcze inaczej można przekazywać wartości, ale nie o tym.

Staraj się nie mieszać angielskiego z polskim.

$weryfikacja = new Weryfikacja;
$data_rejestracji = time();

tu masz w pełni po polsku, a tutaj już:
$weryfikacja->checkMail(...)

pomieszane trochę, co nie wygląda na dobre.


A powiem Ci że w momencie w którym wklejałem to sam o tym pomyślałem, lepiej trzymać się jednej koncepcji, fakt!
Sephirus
Dla uproszczenia kod:

  1. $stmt -> bindValue(':login', $login, PDO::PARAM_STR);
  2. $stmt -> bindValue(':haslo', $haslo, PDO::PARAM_STR);
  3. $stmt -> bindValue(':mail', $email, PDO::PARAM_STR);
  4. $stmt -> bindValue(':kod', $weryfikacja->zrobKod(), PDO::PARAM_STR);
  5. $stmt -> bindValue(':data_rejestracji', $data_rejestracji, PDO::PARAM_STR);
  6. $stmt -> execute();


Można zamienić na:

  1. $stmt->execute(array(
  2. 'login' => $login,
  3. 'haslo' => $haslo,
  4. // itd...
  5. ));


1. Dwukropek przy bindowaniu jest niepotrzebny
2. ::bindValue domyślnie ma 3 argument jako PDO::PARAM_STR
3. można użyć skróconej formy poprzez podanie tablicy parametrów do execute wink.gif

Twoja metoda aczkolwiek jest o wiele dokładniejsza - więc może tak zostać jak najbardziej - wiedz jednak, że da się inaczej wink.gif
hunter1988
Dobrze wiedzieć, warto ogólnie rozumieć co się wykorzystuje i co jest domyślnie aby unikać błędów i niepotrzebnego kodu, jednak zostanę przy tym jak mam, na pewno będzie to rozsądniejsze dla początkującego jak będę używał pełnych rozwiązań, wtedy widzę co gdzie i dlaczego mogę zmienić, aczkolwiek dziękuję po raz kolejny za pomoc wink.gif

Ps. dziś rozmawiam z kolegą i mówię mu, że znalazł się pomocny użytkownik na forum i ruszyłem trochę, więc szykuje się flaszka kurierem biggrin.gif
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.