Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

3 Stron V   1 2 3 >  
Reply to this topicStart new topic
> prawidlowe OOP , struktura klasy, Jak wedlug koncepcji OOP napisac dobra klase
rahul
post
Post #1





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Witam
Temat pewnie wam znany i stary jak swiat. Pisze sobie swoj cms starajac sie zrobic to obiektowo. Dotychczas przejrzalem i przeczytalem wiele artykulow dotyczacych OOP i robie sie coraz glupszy bo z tego co rozumie to zastosowan jest multum, tylko ktore to najlepsze. mam taka klase

  1. include_once('db/db.php');
  2. class User
  3. {
  4. private $user_id;
  5. private $first_name;
  6. private $last_name;
  7. private $login;
  8. private $password;
  9. private $email;
  10. private $ip;
  11. private $user_role;
  12. private $registration_date;
  13. private $db;
  14.  
  15. function __construct()
  16. {
  17. $this->db = Database::getInstance();
  18. }
  19.  
  20. function setLogin($login)
  21. {
  22. $this->login = $login;
  23. }
  24.  
  25. function setPassword($password)
  26. {
  27. $this->password = $password;
  28. }
  29.  
  30. function setFirstName($firstName)
  31. {
  32. $this->firstName = $firstName;
  33. }
  34.  
  35. function setLastName($lastName)
  36. {
  37. $this->lastName = $lastName;
  38. }
  39.  
  40. function setEmail($email)
  41. {
  42. $this->email = $email;
  43. }
  44.  
  45. function setUserRole($role)
  46. {
  47. $this->role = $role;
  48. }
  49.  
  50. function setRegistrationDate($registration_date)
  51. {
  52. $this->registration_date = $registration_date;
  53. }
  54.  
  55.  
  56. function login()
  57. {
  58. $action = $this->db->prepare("SELECT * from users WHERE login LIKE '$this->login'
  59. AND password LIKE '$this->password'");
  60. $action->execute();
  61. $result = $action->fetchAll();
  62. if(count($result)== 1)
  63. {
  64. if($result[0]['Role'] == 0)
  65. {
  66. $_SESSION['user_id'] = $result[0]['user_id'];
  67. return true;
  68. }else if($result[0]['Role'] == 1)
  69. {
  70. $_SESSION['user_id'] = $result[0]['user_id'];
  71. $_SESSION['admin'] = 'admin';
  72. header('location:admin.php');
  73. }
  74. }
  75. return false;
  76. }
  77.  
  78. function register()
  79. {
  80. $ip = $_SERVER['REMOTE_ADDR'];
  81. $action = $this->db->query( "INSERT into users(user_id , Login , Password , Name , LastName ,Email , Ip , Role , RegistrationDate)
  82. VALUES('' , '$this->login' ,'$this->password' , '$this->firstName' , '$this->lastName' , '$this->email' , '$ip' ,
  83. '$this->role' , NOW())");
  84. $action->execute();
  85. return true;
  86. }
  87.  
  88. function EditUser()
  89. {
  90. ...
  91. }
  92.  
  93. function ChangePassword()
  94. {
  95. ...
  96. }
  97. } // end of class.
  98. ?>


Pierwsze pytanie : Czy klasa User powinna miec funkcje takie jak Loguj, Rejestruj, Edytuj, Zmien Haslo i czy te funckje powinny miec juz "hardcoded" zapytania do bazy wewnatrz, patrz funckja loguj();. Wywoluje ja tak:

  1.  
  2. $user_c = new User();
  3. $user_c->setLogin($_POST['login']);
  4. $user_c->setPassword(md5($_POST['password']));
  5. $login = $user_c->login();


Jezeli cos tego pokroju jest ok to spoko. Teraz np dopisalem sobie taka funkcje to tej samej klasy, ktora jak dla mnie moglaby byc w kazdej prawie innej klasie :

  1. class User {
  2.  
  3. private $sqlObj;
  4. private $SqltableRows;
  5.  
  6. function query($query)
  7. {
  8. $sql = $this->db->query($query);
  9. $sql->execute();
  10. $this->sqlObj= $sql->fetchAll(PDO::FETCH_OBJ);
  11. $this->SqltableRows= $sql->fetch(PDO::FETCH_ASSOC);
  12. }
  13. }


Dzieki tej funkcji lapie sobie wszystko z bazy i w prosty sposob moge wywolywac wszystkie kolumny :
  1. $user_c = new User();
  2. $user_c->query("SELECT * FROM users");
  3. $users = $user_c->getObj();
  4. foreach ($users as $user)
  5. {
  6. echo $user->Name;
  7. echo $user->Password;
  8. }


Bardzo podoba mi sie mozliwosc poboru rekordow i nazw wierszy tabeli w tak prosty sposob. Teraz do rzeczy :
Funckja ta jest w Users ale generalnie moglaby byc w prawie kazdej innej klasie, np Products, Articles itp. Czy mam utworzyc osobna klase z ta funckja z ktorej jakos beda kozystac wszyskie inne klasy ? Czy ma byc to w klasie bazy danych, czy moze w jakies jeszcze innej ?

Prosze o odpowiedzi i wyrozumialosc (IMG:style_emoticons/default/smile.gif)


Ten post edytował rahul 20.08.2011, 20:50:56
Go to the top of the page
+Quote Post
Noidea
post
Post #2





Grupa: Zarejestrowani
Postów: 226
Pomógł: 61
Dołączył: 20.08.2010

Ostrzeżenie: (0%)
-----


Cytat
Pierwsze pytanie : Czy klasa User powinna miec funkcje takie jak Loguj, Rejestruj, Edytuj, Zmien Haslo

Nie. Rozbij to sobie na dwie klasy:
User - zwykły kontener na login, hasło, email itd.
UserManager - zarządza użytkownikami (wczytuje, zapisuje, kasuje, itd.)

Cytat
czy te funckje powinny miec juz "hardcoded" zapytania do bazy wewnatrz, patrz funckja loguj();. Wywoluje ja tak:

Zależy. Jak chcesz mieć rozwiązanie, w którym łatwo jest zmienić sposób komunikacji z bazą danych, np. zamiast PDO użyć jakiejś klasy z PEAR, to powinieneś dodać w tym miejscu jeszcze jedną warstwę abstrakcji. Tyle że na 99% nigdy ci się to nie przyda, a tylko skomplikuje kod. Najlepiej wybierz sobie jedną metodę komunikacji z bazą i jej się trzymaj. PDO jest ok.
Z tego rozwiązania które masz wyrzuciłbym tylko pobieranie obiektu PDO z singletona, a zamiast tego przekazywał ten obiekt w parametrze konstruktora

Cytat
  1. $user_c = new User();
  2. $user_c->query("SELECT * FROM users");

To jest źle. User nie powinien nic wiedzieć o wykonywaniu zapytań SQL. Od tego jest PDO


[EDIT]Aha, jeszcze jedno. Operacje takie jak zmiana hasła czy adresu email robisz tak:
  1. <?php
  2.  
  3. class User { /* (...) */ }
  4.  
  5. class UserManager { /* (...) */ }
  6.  
  7. $user = $userManager->getUserByID( $userID );
  8. $user->setPassword( $newUserPassword );
  9. $userManager->updateUser( $user );
  10. ?>

Czyli wystarczy ci jedno duże zapytanie UPDATE aktualizujące wszystkie pola w tabeli z użytkownikami, nawet jeśli zmieniło się tylko hasło, czy tylko email

Ten post edytował Noidea 21.08.2011, 08:18:38
Go to the top of the page
+Quote Post
rahul
post
Post #3





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Dzieki za odpowiedz.
Mam szereg nastepnych pytan.
Po co tak w zasadzie mi podzial na 2 klasy, User, UserManager .. wtedy bede musial wszystkie inne pozostale klasy tez w ten sposob rozbijac. Co mi daje taki zwykly kontener ? Jakos nie bardzo to do mnie przemawia ..

Cytat
  1. $user_c = new User();
  2. $user_c->query("SELECT * FROM users");

To jest źle. User nie powinien nic wiedzieć o wykonywaniu zapytań SQL. Od tego jest PDO


Ok, ale wszystkie funckje typu Loguj, zmien, edytuj i tak wiedza o zapytaniach SQL. Tylko sa one wewnatrz.
Czy funkja query np moglaby byc w klasie z Baza danych?

Cytat
Z tego rozwiązania które masz wyrzuciłbym tylko pobieranie obiektu PDO z singletona, a zamiast tego przekazywał ten obiekt w parametrze konstruktora


Jaka jest wtedy roznica ? Nie do konca widze...

Ten post edytował rahul 21.08.2011, 10:44:28
Go to the top of the page
+Quote Post
Crozin
post
Post #4





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


To z czym masz tutaj do czynienia to mapowanie obiektów do / z zapytań relacyjnej bazy. Innymi słowy, jest to ORM. Napisanie ORM-a, który miałby być zdatny do czegokolwiek jest daleko poza Twoimi obecnymi możliwościami, tak więc nawet nie próbuj brać się za to - skorzystaj z gotowego, solidnego rozwiązania. Osobiście proponuję Doctrine2 bo jest to jedyny duży, PHP-owski ORM o sensownej architekturze.

Cytat
Po co tak w zasadzie mi podzial na 2 klasy, User, UserManager .. wtedy bede musial wszystkie inne pozostale klasy tez w ten sposob rozbijac. Co mi daje taki zwykly kontener ? Jakos nie bardzo to do mnie przemawia
Obiekty różnych typów zajmują się różnymi rzeczami. Zawsze powinieneś starać się doprowadzić do tego by jeden obiekt zajmował się tylko jedną rzeczą. Reprezentowanie danych z bazy danych (obiekt User) i zarządzanie takimi "reprezentantami" (obiekt UserManager) to dwie zupełnie inne sprawy. Oba te obiekty wykonują zadania kompletnie nie związane ze sobą. Dlatego też muszą to być osobne obiekty.

Cytat
Jaka jest wtedy roznica ? Nie do konca widze...
Pobierając obiekt z singletona, tworzysz "z dupy zależność" (jak to sobie zawsze określam). Poczytaj wątki o Dependency Injection [Container] (DI[C]) bo wałkowanie tej dyskujsji po raz n-ty jest męczące. W skrócie: może sam jeszcze nie dostrzegasz tego, ale to same problemy.

Go to the top of the page
+Quote Post
rahul
post
Post #5





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Cytat
Obiekty różnych typów zajmują się różnymi rzeczami. Zawsze powinieneś starać się doprowadzić do tego by jeden obiekt zajmował się tylko jedną rzeczą. Reprezentowanie danych z bazy danych (obiekt User) i zarządzanie takimi "reprezentantami" (obiekt UserManager) to dwie zupełnie inne sprawy. Oba te obiekty wykonują zadania kompletnie nie związane ze sobą. Dlatego też muszą to być osobne obiekty.

Ok,staram sie to poukladac w glowie. Powiedz mi wtedy czy dobrze to rozumie :
1)klasa User bedzie zawierac funkcje do wyswielania danych uzytkownika takie jak np: pokaz imie, pokaz nazwisko, poka mail. I generalnie tylko takie.
2)Z tego co tak sobie mysle to wszystkie podstawowe informacje o uzytkowniku mozna przeciez wywolas z jednej funckji ("select * form user WHERE id = $id") zwroci mi tablice badz obiekt i sobie bede juz nim operowal zaleznie od tego co chce pokazac, tak ?(IMG:style_emoticons/default/smile.gif) Czy niby mam do imienia, nazwiska, maila pisac po osobnej funckji ? Chyba nieee... , co ? W momencie jak zapytanie zwroci mi obiekt mam mam z niego kozystac tak :
  1.  
  2. $user_o = $User->getUser($id);
  3. echo $user_o->Name;

badz tak :

  1.  
  2. $user_o = $User->getUser($id);
  3. echo $user_o['Name']


czy jakos inaczej ?
bo chyba nie tak :
  1.  
  2. $user_o = $User->getUser($id);
  3. echo $user->getName();


Strasznie duzo seterow geterow bym wtedy musial pisac. Czy moze tak trzeba? Wydaje mi sie ze funckja UserManager powinna je raczj miec.

3)Teraz druga klasa User Manager ona bedzie miala funckje typu Loguj, Edytuj, Rejestruj i bede z niej kozystal tak jak napisal Noidea w jednej z odpowiedzi, tak?

A co do seterow i geterow czy tylko klasa UserManager bedzie je posiadala (setPass, setName) takowe w klasie User nie sa mi chyba potrzebne, prawda ?
no i niektore funckje beda sie chyba powtarzac jak np getUserById($id).

Ten post edytował rahul 22.08.2011, 16:08:53
Go to the top of the page
+Quote Post
Crozin
post
Post #6





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


1. Coś w ten deseń. Mając przykładowo obiekt User z właściwościami id, email, firstName, lastName możesz mieć metody get/setId(), get/setEmail(), get/setFirstName(), get/setLastName(), getFullName() - w miarę możliwości bardzo proste, podstawowe operacje.
2. Właśnie raczej powinno to być $user->getEmail() itp. Tego pisania wcale nie ma jakoś specjalnie dużo, zresztą pierwsze lepsze IDE, RMB -> Source -> Generate Getters and Setters -> Select All -> OK, i po sprawie.
3. Nie, taki obiekt UserManager powinien mieć co najwyżej metody w stylu save($u), update($u), delete($u), jakieś najbardziej podstawowe pobieranie danych findOne($id), findAll(). Jedynie rzeczy związane z bezpośrednim zarządzaniem "reprezentantami".
Takie rzeczy jak rejestracja czy logowanie to już skomplikowane, wielostopniowe procesy. Przecież takie zalogowanie użytkownika to pobranie danych, sprawdzenie ich poprawności, obsługa błędów, pobranie danych w przypadku podania prawidłowych danych, wykonanie jakiś operacji w bazie danych (typu zapisanie informacji o logowaniu w logach) i przekierowanie użytkownika. Tak mniej-więcej ten proces wygląda w najprostszym wydaniu. Przy jego obsłudze udział bierze wiele różnych obiektów.

Cytat
A co do seterow i geterow czy tylko klasa UserManager bedzie je posiadala (setPass, setName) takowe w klasie User nie sa mi chyba potrzebne, prawda ?
Gettery i settery spotkasz w całej masie obiektów, bo jest to nic innego jak tylko nazwa dla pewnych konstrukcji w kodzie, bardzo popularnych zresztą. (http://en.wikipedia.org/wiki/Accessor_method)
Cytat
no i niektore funckje beda sie chyba powtarzac jak np getUserById($id).
Tzn?

PS. OOP ma to do siebie, że jego zalety wychodzą na jaw dopiero w nieco większych projektach. Co więcej by OOP jako takie miało sens konieczne jest by cała architektura była obiektowa. Pięć klas na krzyż nie wystarczy.

Ten post edytował Crozin 22.08.2011, 17:02:24
Go to the top of the page
+Quote Post
rahul
post
Post #7





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Dzieki Crozin, szczegolnie za cierpliowac , tak sobie patrze na forum i widze ze juz udzielales po wiele razy tego typu odpoweidzi a jakos nam to do glow tak latwo nie wchodzi.
Mam takie wrazenie ze wlasnie ta moja obiektowka to w zasadzie programowanie proceduralne tylko opakowane w klasy z niektorymi bajerami OOP. Ciezko jest natomiast zrobic kolejny krok do przodu.
Zdaje sobie sprawe ze w wiekszych projektach pewnie ma to sens. Czy zatem myslisz ze i tak warto OOP probowac uzywac w swoich malych stronkach , nawet jak to ma byc 5-10 klas na krzyz ?
A co do Loginu to gdzie zatem taka funkcje, badz rejestracje umiescic jezeli nie w klasie UserManager.
Co do Dependency Injection to zaczalem cos czytac ale bede pewnie niedlugo znow sie odzywal bo znajac sie zrozumie tam cos na opak (IMG:style_emoticons/default/smile.gif)
elo.
Go to the top of the page
+Quote Post
melkorm
post
Post #8





Grupa: Zarejestrowani
Postów: 1 366
Pomógł: 261
Dołączył: 23.09.2008
Skąd: Bydgoszcz

Ostrzeżenie: (0%)
-----


OOP - sam miałem z tym wiele problemów na początku, ciągłe pytania:

- po co?
- dlaczego ?
- przecież można w jednym miejscu i z głowy
- ale tak mniej kodu
itd. itp.

Na szczęście miałem ten plus że miałem swego typu `mentora` do którego mogłem się zwrócić o każdą duperelę, lecz wciąż pozostawał pewien niedosyt, aspekt nie zrozumienia / nieogarnięcia całości - oświecenie przyszło gdy zacząłem pisać w pierwszym FW autorstwa mojego brata (mentora ;p), na początku wydawał mi się fajny, zacząłem go poznawać, przeglądać kod itp i zacząłem zauważać braki, błędy i problemy aż w końcu zrozumiałem cały organizm, lecz wciąż pozostawał mały niedosyt na temat OOP bo ja tu się uczyć na niedoskonałym dziecku? Więc zacząłem szukać FW który najlepiej implementuje wszelkie wzorce projektowe, a do tego mnie nie ogranicza lecz jest bardziej biblioteką niż samym FW - co dawało mi większość możliwość jego poznania przez odpalenie, konfigurację i badanie zachowań - mowa tutaj o Zend Framework, tak na prawdę dopiero używając tego narzędzia i po przeczytaniu ton materiałów w necie (tutaj duży plus dla Zyx'a za jego blog) i wielu innych forumowiczów których blogi czytam namiętnie szczególnie gdy pojawia się temat z okolic OOP/wzorców projektowych.

Trzeba tutaj także wspomnieć o praktyce, moim zdaniem najlepiej postawić sobie cel by coś napisać i spojrzeć na to z perspektywy osoby która by miała tego używać i ile trudności by to jej sprawiło - ponieważ w większości wypadków im trudniej coś zaimplementować u siebie tym gorszej jakości to jest. Ja osobiście wielokrotnie coś pisałem i przepisywałem to po 3 - 5 razy by osiągnęło swój ostateczny kształt ponieważ w momencie używania zacząłem zauważać braki w implementacji i używalności.

W skrócie: czytać, pisać, pisać, czytać i jeszcze raz pisać.
Go to the top of the page
+Quote Post
rahul
post
Post #9





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Taaaa...
wlasnie pisze swojego cms'a po raz 2 i kurde juz widze ze musze cos zmieniac przepisywac i tylko mnie trafia wtedy bo chce to jak najbardziej uproscic.
Fajnie ze miales mentora. Ja niesteyt jeszcze z tych dokumentacji o frame workach nie duzo kumam (IMG:style_emoticons/default/smile.gif)
Mam zamiar zaczac od Kohany bo chyba z nia bede mial najmniej problemow , potem tylko zend i symphony :]
A co do OOP to gdzie ten Login w ktorej kurde klasie w koncu i rejestracja jezeli nie u uzytkownika anie jego managera. Najgorsze jest to ze moj nauczyciel tlumaczyl to OOP i teraz wszystko jest sprzeczne. Uzywal tego singletona zamiast DI ktorego jeszcze nie do konca ogarnalem i wszystkei funkcje zwiazane z uzytkownikiem walal do uzytkownika bo mowil ze po co sobie komplikowac.
Go to the top of the page
+Quote Post
by_ikar
post
Post #10





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Zamiast tworzyć ileś tam tych seterów i geterów, możesz napisać jeden get i jeden set a dane z nich pobierać tak:

Kod
$user = new User();
$user->get('id');
$user->get(array('id', 'first_name', 'last_name'));
$user->set('first_name', 'Janek');
$user->update(array('first_name' => 'Janek', 'password' => 'secret'));
$user->clear('last_name');
$user->clear('last_name', 'hobby');


Moim zdaniem takie podejście mniej więcej, jest lepsze. Powiedzmy że masz z poziomu jakiegoś panelu admina, dodania dodatkowego pola w profilu użytkownika (społecznościówki itp) i w przypadku takim musiałbyś chyba ręcznie dodawać seter/geter do klasy, a tak pobierasz sobie jedną metodą to co ci potrzeba. Ostatnio ktoś się nawet pytał o to na forum. Polecam czytać częściej forum, albo zadawać trafniejsze pytania do wyszukiwarki.
Go to the top of the page
+Quote Post
Crozin
post
Post #11





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


@by_ikar: Zerowe wsparcie ze strony IDE czy narzędzi dokumentujących. "Wymagająca" implementacja takich metod. Utrudnienia przy nadpisywaniu. Niezbyt to wygodne. Co do przykładu z panelem... nienajlepszy, zakłada istnienie błędnej struktury danych.
Go to the top of the page
+Quote Post
by_ikar
post
Post #12





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Nie wiem z jakiego ID korzystasz, ale mój podpowiada mi składnie jeżeli tak tworzę metody. Jest to jedno z rozwiązań. Co w przypadku kiedy ma się powiedzmy 50-70 pól w takim użytkowniku, to wtedy ma mieć 70 takich metod? Nie wiem, może mamy różne podejście, ale dla mnie jest to śmieszne i raczej nie przyjdzie dzień w którym takie coś popełnię.

To albo mu pozostaje magia, co raczej nie daje w żadnym IDE wsparcia, albo klepanie nowych metod jak tylko doda nowe pole. Tak się zastanawiam nad tym co piszesz, i w sumie jednak będę obstawiał przy swoim. W symfony 2 masz container który trzyma masę obiektów, i właśnie w taki sposób się je pobiera/dodaje. Można pobrać dane obiekty w setXXXService/getXXXService tyle że jest to magia i raczej w większości tego co widziałem w symfony, obiekty pobiera się get('xxx') i jak narazie jesteś pierwszą osobą która piszę że jest to złe rozwiązanie. Może i jest. Nie mniej, moje zdanie jest takie, że jest to lepsze, niż magia, czy klepanie za każdym razem nowych geterów/seterów, zwłaszcza w takim obiekcie jak DI.
Go to the top of the page
+Quote Post
starach
post
Post #13





Grupa: Zarejestrowani
Postów: 999
Pomógł: 30
Dołączył: 14.01.2007
Skąd: wiesz ?

Ostrzeżenie: (0%)
-----


Metody magiczne i po problemie. (IMG:style_emoticons/default/smile.gif)

  1.  
  2. /**
  3.  * @property string $sPHPJestKiepskie guzik prawda ale type hinting jest ;)
  4.  */
  5. class Klasa
  6. {
  7. private $_mojeZajefajneZmienne = array();
  8. public function __get($var) {
  9. return $this->_mojeZajefajneZmienne[$var];
  10. }
  11. public function __set($var, $val)
  12. {
  13. $this->_mojeZajefajneZmienne[$var] = $val;
  14. }
  15. }
  16. $k = new Klasa();
  17. $k->sPHPJestKiepskie = 'terefere';

Oczywiście jeszcze powinieneś dodać do tych metod jakąś walidację, ale w sumie to zależy od sytuacji. A metody tworzysz tylko w przypadku wykonania jakiejś operacji na zmiennej.

Edit:
Cytat(by_ikar @ 23.08.2011, 00:12:56 ) *
(...) i jak narazie jesteś pierwszą osobą która piszę że jest to złe rozwiązanie. (...)

To ja będę drugą. (IMG:style_emoticons/default/tongue.gif)

Ten post edytował starach 22.08.2011, 23:19:40
Go to the top of the page
+Quote Post
Crozin
post
Post #14





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


Mając 70 publicznych właściwości w obiekcie get*() vs get('*') jest najmniejszym problemem.
Co do DIC-a z Symfony2... co on ma tutaj w ogóle do tematu? To jest kontener, a Container::get() zwraca element w nim przechowywany. Temat dotyczy operowania na właściwościach obiektu.
Jeszcze co do "dodawania pola"... to tworzy się kontener, do którego możesz sobie wrzucić dowolną ilość nowych pól, a nie modyfikuje kod.

@starach: Jeszcze gorsza i bardziej bezsensowna metoda.

Ten post edytował Crozin 22.08.2011, 23:26:34
Go to the top of the page
+Quote Post
melkorm
post
Post #15





Grupa: Zarejestrowani
Postów: 1 366
Pomógł: 261
Dołączył: 23.09.2008
Skąd: Bydgoszcz

Ostrzeżenie: (0%)
-----


To jeżeli już tym torem idziemy to zrobić to jak ma Zend, czyli dla ActiveRecordu pobiera z metadanych listę pól dla tabelki i jak chcemy coś ustawić co się nie znajduje w tabelce to dostaniemy exceptionem (IMG:style_emoticons/default/wink.gif)


Ale sam także jestem przeciwnikiem __set i __get lub jakichś ich kopii typu set, get, clear, za miesiąc usiądziesz i będzie "eeee jakie ta tabela miała pola ...", raz wpisać i po problemie moim zdaniem, lub napisać generator co nie jest na prawdę trudne, sam tak robię i po problemie.
Go to the top of the page
+Quote Post
starach
post
Post #16





Grupa: Zarejestrowani
Postów: 999
Pomógł: 30
Dołączył: 14.01.2007
Skąd: wiesz ?

Ostrzeżenie: (0%)
-----


Hmm, a możecie napisać co wy macie przeciwko tej metodzie? :|

(IMG:http://img854.imageshack.us/img854/2071/phptypehintingformagicg.th.jpg)
Go to the top of the page
+Quote Post
Crozin
post
Post #17





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


A po co korzystać z metod magicznych skoro:
  1. class Abc {
  2. public $phpJestKiepskie;
  3. }
  4.  
  5. $abc->phpJestKiepskie = 'terefere';
  6.  
  7. class Abc {
  8. public $params = array();
  9. }
  10.  
  11. $abc->params['phpJestKiepskie'] = 'terefere';
  12.  
  13. class Abc {
  14. private $params = array();
  15.  
  16. public set($param, $value) {
  17. $this->params[$param] = $value;
  18. }
  19. }
  20.  
  21. $abc->set('phpJestKiepskie', 'terefere');
Działają równie dobrze, a nie wprowadzają bezsensownych mechanizmów. To, że PHP wspiera metody magiczne* nie oznacza, że trzeba z nich korzystać. Na dobrą sprawę bardzo ciężko jest dla nich znaleźć sensowne zastosowanie poza ratowaniem się przed utratą wstecznej kompatybilności w pewnych przypadkach.

* te prawdziwie magiczne, bo przykładowo konstruktory z magią niewiele mają wspólnego.
Go to the top of the page
+Quote Post
starach
post
Post #18





Grupa: Zarejestrowani
Postów: 999
Pomógł: 30
Dołączył: 14.01.2007
Skąd: wiesz ?

Ostrzeżenie: (0%)
-----


Jest jeden argument za tym żeby je właśnie stosować. Jest nim podpowiadanie składni, którego próżno szukać w pozostałych dwóch przykładach, które podałeś. Co na dobrą sprawę już zarzuciłeś w poprzednim poście kierowanym do ~by_ikar.

Natomiast różnica między metodą magiczną, a sposobem stosowanym zarówno przez ciebie jak i powszechnym w świecie programistów, czyli pisanie setterów i getterów jako oddzielnych metod jest chyba widoczna na pierwszy rzut oka. Mniej kodu! Zarówno do napisania przez ciebie jak i do sparsowania. Do tego przejrzystość, bo pisząc metodę która zwraca np. Nazwisko, wiesz że musi ona mieć jakiś głębszy sens i służyć do czegoś więcej niż tylko do zwrócenia lub ustawienia zmiennej.

Nie mam nic na dobrą sprawę przeciwko setterom i getterom na zasadach metod, bo w NetBeans wystarczy zrobić listę zmiennych a potem można sobie wygenerować settery i gettery. Niemniej jednak wolę metodę magiczną z wymienionych wyżej względów.
Go to the top of the page
+Quote Post
Crozin
post
Post #19





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


@starach:
Pierwszy przykład to przykład poprawnie zdefiniowanej właściwości obiektu, bez niepotrzebnych hacków pokroju @param przy deklaracji klasy. Dwa ostatnie to już natomiast (bez)pośrednie odniesienia do kontenera będącego właściwością obiektu.
Swoją drogą nie wydaje Ci się śmieszne jawne zadeklarowanie w dokumentacji, że obiekt ma jakąś właściwość, po czym celowo jej nie zdefiniować tylko po to, żeby zaraz po tym napisać obejście w postaci metod magicznych __get() i __set() rozwiązujących problem niezdefiniowanej właściwości. Dlaczego po prostu chcąc mieć właściwość dla obiektu nie zdefiniujesz jej?

Cytat
Natomiast różnica między metodą magiczną, a sposobem stosowanym zarówno przez ciebie jak i powszechnym w świecie programistów, czyli pisanie setterów i getterów jako oddzielnych metod jest chyba widoczna na pierwszy rzut oka. Mniej kodu! Zarówno do napisania przez ciebie jak i do sparsowania.
Co z tego, że mniej kodu, skoro mniej znacznie gorszego pod względem wydajności czy łatwości modyfikacji kodu? Ten durny kod natomiast możesz sobie w łatwy sposób automatycznie wygenerować, zresztą jego napisanie zajmuje co najwyżej minuty co przy kilkuset godzinach spędzonych nad projektem nie jest zbyt przytłaczające. A o parser się nie martw... kilka dodatkowych bajtów mu nie zaszkodzi.
Cytat
Do tego przejrzystość, bo pisząc metodę która zwraca np. Nazwisko, wiesz że musi ona mieć jakiś głębszy sens i służyć do czegoś więcej niż tylko do zwrócenia lub ustawienia zmiennej.
A korzystając z obiektu interesuje mnie wyłącznie jego interfejs. Implementacja metody (w ogóle całego obiektu) jest nieistotna.
Go to the top of the page
+Quote Post
melkorm
post
Post #20





Grupa: Zarejestrowani
Postów: 1 366
Pomógł: 261
Dołączył: 23.09.2008
Skąd: Bydgoszcz

Ostrzeżenie: (0%)
-----


Jestem absolutnie za Crozin'em, wchodząc w źródło klasy wolę zobaczyć masę setterów i getterów niż dwie magiczne metody które nic mi nie mówią, w dodatku załóżmy że będziesz musiał coś dodać przy ustawianiu jakiegoś pola np. $foo->bar, tak to korzystałeś z __set i się automatycznie ustawiało i teraz cały kod musisz przelecieć tam dgzie to ustawisz by to poprawić, a tak dopisujesz w metodzie setBar i tyle, to sam otyczy się getBar vs $foo->bar.

Ogólnie nie lubię metod magicznych i ogólnie widać trend odchodzenia od nich przez głównych graczy np Zend'a (wersja 2.0) .
Go to the top of the page
+Quote Post
by_ikar
post
Post #21





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Cytat
Ale sam także jestem przeciwnikiem __set i __get lub jakichś ich kopii typu set, get, clear, za miesiąc usiądziesz i będzie "eeee jakie ta tabela miała pola ...", raz wpisać i po problemie moim zdaniem, lub napisać generator co nie jest na prawdę trudne, sam tak robię i po problemie.


Ale to jest tylko i wyłącznie wasze zdanie. Nie to że jestem jakimś fanbojem symfony, bo nie jestem, nigdzie go nawet nie wykorzystuje. Ale tam przykładowo jest obiekt ParametrBag, który operuje na tablicy. Najwięcej jest go chyba w obiekcie request. I powiedzmy teraz przykład, masz sobie tablicę $_SERVER lub jeszcze lepiej, tablicę $_POST. Nie wiesz na dobrą sprawę co w tej tablicy jest. To wtedy używasz za każdym razem isset żeby sprawdzić czy w tablicy jest dany klucz, tworzysz więcej niż 70 geterów/seterów, bo przecież to jest tablica post, nie wiesz jakich formularzy będziesz potrzebować na kolejnej stronie i co w nich będziesz mieć. To jak wy radzicie sobie z takimi sytuacjami? Dla każdego jednego klucza w tej tablicy piszecie osobno isset? No proszę was panowie, to jest masochizm i zachowanie które nie ma nic wspólnego z DRY, nie mówiąc już o KISS. Nie jestem ekspertem, ale masochistą też nie jestem. Jedno get() które mi sprawdza czy w danej tablicy jest dany klucz, jeżeli nie rzuci wyjątkiem, lub jakąś wartością domyślną (w symfony jest to wartość domyślna). I nie mówię tutaj o magicznym __get() tylko o normalnej metodzie get() która operuje na jakiejś tablicy, w przypadku użytkownika również na tablicy. Więc albo korzystacie bezpośrednio z tablicy $_POST i walicie dziesiątki issetów/warunków sprawdzających te tablicę, albo na "zaś" napierdzielacie pierdyliard seterów/geterów.

Co ma wspólnego DCI z symfony z tym o czym mówię? http://components.symfony-project.org/depe...book/04-Builder istnieje jeden geter i jeden seter do pobrania obiektu, niema tak że dla każdego obiektu jest tworzony nowy seter/geter bo wtedy moim zdaniem to by było mało używalne. Jak wy sobie wyobrażacie przy każdej zmianie tablicy tworzenie nowego setera/getera? Pół biedy jak sami chcemy skorzystać z DCI, a w takim symfony gdzie klas jest dobrych kilka stówek, to miałbym tworzyć dla każdej klasy nowy seter/geter? Trochę dziwne macie podejście, co kto lubi.

Dla mnie to jest masakra, o czym piszecie, rozumiem kiedy się wie dokładnie jakie metody ma mieć klasa, to i można tworzyć nawet 30 seterów/geterów chociaż ja już wtedy zrobił bym jednego wspólnego getera i setera. Ale w przypadku kiedy operujemy na danych które mogą być różne, pisanie na zaś albo dopisywanie nowego getera/setera i modyfikacja połowy systemu, bo przecież nie mogę skorzystać z get('klucz'), więc muszę połowę klas które z tego obiektu korzystają zmodyfikować. Nie wiem, jestem za minimalizmem, oczywiście nie przesadzonym żeby zaraz czarować __get/__set, ale zdecydowanie za minimalizmem, i raczej takie metody uniwersalne mnie kręcą niż napierdzielanie bezsensu pierdyliarda kolejnych metod, bo pomyślałem że mogę dodać nowe pole dla użytkownika..

Polecam wam przejrzeć w symfony, bo tam często i gęsto używa się tego typu podejścia.

Jeszcze inny przykład, templatki, nie wiesz jakie zmienne będziesz dodawać, więc jest jedna wspólna metoda add/assign, jak wy, wyobrażacie sobie aby tworzyć pierdyliard nowych metod i modyfikowanie klas, dlatego że dodam do swojego layoutu jakieś dodatkowe dane? W wielu miejscach dostrzegam takie podejście i tak jak mówię, jesteście pierwszymi 2 osobami które mają jakieś halo odnośnie takiego rozwiązania.

To oczywiście wasza sprawa jak piszecie, pewnie i tak więcej umiecie/wiecie odemnie, nie mniej chciałem przekazać swoje zdanie na ten temat.

EDIT:

Cytat(Crozin @ 23.08.2011, 00:25:43 ) *
Mając 70 publicznych właściwości w obiekcie get*() vs get('*') jest najmniejszym problemem.


Ahh miałem jeszcze dopisać, 70 to jest get*(), jeszcze przecież masz 70 set*() co daje ci sumkę 140 metod, tylko po to żeby pobrać dane użytkownika (IMG:style_emoticons/default/smile.gif) a gdzie tutaj jeszcze inne metody. W 500 się zamkniemy? Ironia, ale niestety tak to wygląda z mojego punktu widzenia. Dla mnie jest to marnotrawstwo.

Ten post edytował by_ikar 23.08.2011, 07:52:59
Go to the top of the page
+Quote Post
Noidea
post
Post #22





Grupa: Zarejestrowani
Postów: 226
Pomógł: 61
Dołączył: 20.08.2010

Ostrzeżenie: (0%)
-----


@by_ikar Dyskusja o getterach i setterach wyszła od klasy User, której właściwości nie zmieniają co wywołanie strony, więc skąd te argumenty o sprawdzaniu wartości w tablicy POST? Nawet to, co napisałeś na poprzedniej stronie, czyli dodawanie niestandardowych pól do profilu użytkownika, nie wymusza korzystania z pojedynczych funkcji get() i set() w klasie User:
  1. class User
  2. {
  3. function getLogin()
  4. function setLogin( $login )
  5. function getPassword()
  6. function setPassword( $password )
  7. // (...)
  8.  
  9. function getCustomFields() // Zwraca kolekcję par klucz - wartość opisujących dodatkowe pola profilu użytkownika
  10. }

Później podczas aktualizacji danych użytkownika UserManager porówna klucze tej kolekcji z możliwymi kluczami dodatkowych pól użytkownika. Rozpoznane wartości powędrują do bazy, nierozpoznane zostaną zignorowane (plus dodany zostanie wpis do logów)

@rahul Funkcje login(), logout(), register() mają być "jeden poziom wyżej" niż UserManager (nie podałeś co jest u ciebie tym poziomem).
Np. jeśli korzystasz ze wzorca MVC, to funkcje te będziesz miał w modelu. Zostaną wywołane z kontrolera, zrobią to co mają zrobić (walidacja, operacje na bazie przy użyciu UserManagera, zapisanie informacji w sesji) i zwrócą rezultat kontrolerowi, który zdecyduje co dalej zrobić (np. przekierowanie na inną stronę)
Go to the top of the page
+Quote Post
rahul
post
Post #23





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Rozumiem. Ze wzorca mvc poki co nie kozystam, to chyba dopiero przyjdzie przy uzyciu frameworka, narazie pisze swoj cms'sik i chce zrobic jakis sensowny podzial na klasy i zrozumiec co gdzie dawac.
Czy odrazu powinienem robic mvc ?:/
Go to the top of the page
+Quote Post
by_ikar
post
Post #24





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Kod
Dyskusja o getterach i setterach wyszła od klasy User, której właściwości nie zmieniają co wywołanie strony, więc skąd te argumenty o sprawdzaniu wartości w tablicy POST? Nawet to, co napisałeś na poprzedniej stronie, czyli dodawanie niestandardowych pól do profilu użytkownika, nie wymusza korzystania z pojedynczych funkcji get() i set() w klasie User:


Niby tak, lecz wciąż nie wiesz ile tych pól będzie miał autor tematu, jeżeli to będzie tak jak wyżej napisałem 70 pól, wówczas masz 140 metod samych geterów i seterów. No ale co kto lubi. Każda modyfikacja bazy = modyfikacja klasy user. Gdyby to była magia to pretensje mieć można. Niby nie wymusza, bo pola są powiedzmy stałe, lecz w każdym seterze/geterze trzeba niemal powielać warunki, bo albo stworzysz jedną metodę has, którą będziesz w 140 metodach powielał; albo za każdym razem tworzysz warunek, co z DRY i KISS nie ma nic wspólnego.

Wraca po kilku miesiącach do projektu, i nie wie jakie tam były pola, no ale przecież istnieje metoda getAll() która zwraca wszystkie klucze. Zresztą sam zdecyduje co będzie robić. Wszystko, byleby nie magia. Jak ci wygodnie jest klepać pierdyliard metod, to twoja mańka.

Odniosłem się do przykładów z między innymi tablicą post, jako przykładu, że w tej tablicy nie zawsze wiesz co ląduje, i tworzenie dla tej i podobnych tablic pierdyliarda metod i warunków sprawdzających czy klucz istnieje jest zwyczajnym bezsensem (dla mnie) i niepotrzebnym powielaniem kodu (DRY).
Go to the top of the page
+Quote Post
melkorm
post
Post #25





Grupa: Zarejestrowani
Postów: 1 366
Pomógł: 261
Dołączył: 23.09.2008
Skąd: Bydgoszcz

Ostrzeżenie: (0%)
-----


@by_ikar, to o czym mówisz to inna baja wtedy robi się setParam i getParam i do tego ArrayObject i tyle, też nie ma mowy o __set i __get (IMG:style_emoticons/default/wink.gif)
Go to the top of the page
+Quote Post
Crozin
post
Post #26





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


@by_ikar: Pisałem to już wcześniej... temat jest o właściwościach obiektu, a Ty piszesz o obiekcie-kontenerze.
Cytat
Ahh miałem jeszcze dopisać, 70 to jest get*(), jeszcze przecież masz 70 set*() co daje ci sumkę 140 metod, tylko po to żeby pobrać dane użytkownika a gdzie tutaj jeszcze inne metody. W 500 się zamkniemy? Ironia, ale niestety tak to wygląda z mojego punktu widzenia. Dla mnie jest to marnotrawstwo.
OK, widzę że nie zrozumiałeś. Mając 70 publicznych właściwości (nie mylić z elementami w kontenerze) masz obiekt, który nigdy nie powinien powstać.
Go to the top of the page
+Quote Post
mike
post
Post #27





Grupa: Przyjaciele php.pl
Postów: 7 494
Pomógł: 302
Dołączył: 31.03.2004

Ostrzeżenie: (0%)
-----


~by_ikar zainteresuj się takim pojęciem jak kohezja (oczywiście w kontekście programowania).
Po co w ogóle rzucasz argumentami o tylu właściwościach skoro wszyscy (wszyscy?) wiemy, że taka klasa byłaby tragedią?
Go to the top of the page
+Quote Post
rahul
post
Post #28





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Cytat
OK, widzę że nie zrozumiałeś. Mając 70 publicznych właściwości (nie mylić z elementami w kontenerze) masz obiekt, który nigdy nie powinien powstać

(IMG:style_emoticons/default/tongue.gif)
Go to the top of the page
+Quote Post
by_ikar
post
Post #29





Grupa: Zarejestrowani
Postów: 1 798
Pomógł: 307
Dołączył: 13.05.2009
Skąd: Gubin/Wrocław

Ostrzeżenie: (0%)
-----


Kod
@by_ikar: Pisałem to już wcześniej... temat jest o właściwościach obiektu, a Ty piszesz o obiekcie-kontenerze.

Też pisałem że to jest tylko porównanie. Dobre by było tworzenie metody dla każdego pola profilu użytkownika jeżeli to by były jakieś podstawowe informacje i wtedy zamykamy się powiedzmy w 10 seterach/geterach. A my nie wiemy co robi autor, więc dałem bardziej uniwersalne rozwiązanie niż klepanie dziesiątek seterów/geterów.

Kod
Po co w ogóle rzucasz argumentami o tylu właściwościach skoro wszyscy (wszyscy?) wiemy, że taka klasa byłaby tragedią?

Rzucam właśnie dlatego, że narazie nikt w tym temacie nie zwrócił na to uwagi i część ludzi mówi żeby klepać setery/getery dla każdego pola profilu użytkownika. Autor zadał pytanie czy musi dla każdego, to też dałem mu odpowiedź że nie musi i może stworzyć jeden geter/seter. Ktoś tam nawet magię zaproponował, złe wyjście, ale chyba lepsze niż do każdego pola użytkownika klepać geter.
Go to the top of the page
+Quote Post
rahul
post
Post #30





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Podsumowanie lekcji ...
czyli co , bedzie to tak mniej wiecej wygladac ?


  1. class User {
  2.  
  3.  
  4. private $id;
  5. private $name;
  6. private $lastName;
  7. private $password;
  8. private $db;
  9.  
  10. public function __construct($db)
  11. {
  12. $this->db = $db;
  13. }
  14.  
  15. public function setName($name)
  16. {
  17. $this->name = $name;
  18. }
  19.  
  20. public function getName()
  21. {
  22. return $this->name;
  23. }
  24.  
  25. public function setLastName()
  26. {
  27. $this->lastName= $lastName;
  28. }
  29.  
  30. public function getLastName()
  31. {
  32. return $this->lastName;
  33. }
  34.  
  35. public function getUserById($id)
  36. {
  37. $sql = $this->db->query("SELECT * from users WHERE user_id= '$id'");
  38. $sql->execute();
  39. $user = $sql->fetch(PDO::FETCH_OBJ);
  40. $this->name = $user->user_FirstName;
  41. $this->lastName = $user->user_LastName;
  42. }
  43.  
  44. }

  1.  
  2. <?php
  3. class UserManager extends User {
  4.  
  5.  
  6.  
  7. public function create()
  8. {
  9.  
  10. }
  11.  
  12. public function update($e)
  13. {
  14.  
  15. }
  16.  
  17. public function delete()
  18. {
  19.  
  20. }
  21.  
  22. public function findAllUsers()
  23. {
  24.  
  25. }
  26. }
  27.  
  28.  


i obsluga ..
  1.  
  2. $db = new Database();
  3. $user = new User($db);
  4.  
  5. // tu do odczytywania uzytkownika
  6. $user->getUserById(55);
  7. echo $user->getName();
  8. echo $user->getLastName();
  9.  
  10. // tu do operacji
  11. $userM = new UserManager($db);
  12. $userM->getUserById(55);
  13. $userM->setName('paradontozaur');
  14. $userM->update();
  15.  


Jestem blisko czy dalej nooooob ?
Go to the top of the page
+Quote Post
starach
post
Post #31





Grupa: Zarejestrowani
Postów: 999
Pomógł: 30
Dołączył: 14.01.2007
Skąd: wiesz ?

Ostrzeżenie: (0%)
-----


Blisko, nawet bardzo. Tylko getByUserId do drugiej klasy i jak dla mnie gitara.
Go to the top of the page
+Quote Post
rahul
post
Post #32





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


no to klawo, mam nadzieje ze reszta mozgowcow tez sie zgadza.
Z tym dziedziczeniem to dobrze , taa ?
Go to the top of the page
+Quote Post
Crozin
post
Post #33





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


1. Po co obiektowi User dostęp do bazy danych? Dlaczego w tej klasie jest metoda getUserById(), skoro definitywnie zadanie dla menadżera użytkowników?
2. W jaki sposób menadżer użytkowników jest wyspecjalizowaną formą użytkownika? Jeżeli nie potrafisz udzielić odpowiedzi na to pytanie oznacza to, że nie powinien on dziedziczyć po klasie użytkownika.

PS. Pisałem już, że mapowanie danych pomiędzy bazą danych i obiektami jest samo w sobie trudnym zadaniem. Na razie odpuść sobie ćwiczenia w tym "sektorze", skorzystaj z gotowego narzędzia które będzie w ogóle działać, a OOP poćwicz sobie na czymś innym.

Ten post edytował Crozin 24.08.2011, 09:20:18
Go to the top of the page
+Quote Post
rahul
post
Post #34





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Cytat
Po co obiektowi User dostęp do bazy danych? Dlaczego w tej klasie jest metoda getUserById(), skoro definitywnie zadanie dla menadżera użytkowników?

myslalem ze aby pokazac dane uzytkownika to musze je najpierw pobrac. Ale ok, niech zatem robi to User Manager.
Cytat
W jaki sposób menadżer użytkowników jest wyspecjalizowaną formą użytkownika? Jeżeli nie potrafisz udzielić odpowiedzi na to pytanie oznacza to, że nie powinien on dziedziczyć po klasie użytkownika.

Dziedziczyl w tym przypadku po to ze jak UserM pobierze informacje o uzytkowniku to je mu odrazu przypisze i moge sie do tych informacji np (getName) odniesc od instancji obiektu User.
Inaczej kurde nie wiem po co mi pusty obiekt User ktory by nic nie robil :/ Jeszcze tym bardziej w momencie jak juz wywale z niego funckje getUserById i przeniose do Managera.
Go to the top of the page
+Quote Post
thek
post
Post #35





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




A nie pomyślałeś, że UserManager poprzez zarządzanie Userami może stać się w pewnych okolicznościach ich kolekcją? Poza tym klasa User chyba jest "samoświadoma" (IMG:style_emoticons/default/wink.gif) Jeśli gdzieś posiadam obiekt klasy user, to chyba ma on możliwośc na rzecz samego siebie wywołać własną metodę.
Innymi słowy...
$userManager->getUserById( 10 )->getName();
Ale klasa UserManager jako return w funkcji getUserById musi zwrócić obiekt klasy User. W ten sposób nastąpi łańcuch metod, gdzie każda kolejna bazuje na obiekcie otrzymanym. Może się przy tym wysypać, jesli nie zostanie zwrócona właściwa, ale od tego są już wyjatki typu Runtime. A co do przypadku "aby pokazac dane uzytkownika to musze je najpierw pobrac" to czy własnie tak nie jest? Dlatego Crozin ma rację wspominając o tym.

A po co pusty obiekt klasy user w managerze? Ano do tworzenia nowego obiektu. Nie mów, że tworząc nowy obiekt inicjujesz go już istniejącym. Nie... Tworzysz pusty, który dopiero uzupełniasz danymi.
Go to the top of the page
+Quote Post
rahul
post
Post #36





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


@thek - Czy zatem obiekt zwrocony z funckji UserManagera->getUserById(10500) mam przekazac w konstruktor klasy User czy w funckji getUserById mam zrobic instancje Usera ?
Go to the top of the page
+Quote Post
Crozin
post
Post #37





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


W skrócie:
  1. class User {
  2. private $id;
  3. private $email;
  4. private $firstName;
  5. private $lastName;
  6. private $dateOfBirth;
  7.  
  8. // standardowe gettery / settery
  9.  
  10. public function getFullName() {
  11. return $this->getFirstName() . ' ' . $this->getLastName();
  12. }
  13.  
  14. public function isAdult() {
  15. return $this->getDateOfBirth() > new \DateTime('-18 years'); // Obiekty typu DateTime mają przeciążone operatory porównania.
  16. }
  17. }
  18.  
  19. class UserManager extends AbstractManager implements UserManagerInterface {
  20. ...
  21.  
  22. public function findOne($id) { // bezsens jest dodawać przyrostek "User", bo dosyć oczywistym jest, że menadżer użytkowników operuje na... użytkownikach
  23. $resultSet = $this->db->...(... $id ...); // pobranie danych
  24.  
  25. if (/* nie znaleziono */) {
  26. return null;
  27. }
  28.  
  29. $user = new User();
  30. $user->setFirstName($resultSet['first_name']);
  31. ...
  32.  
  33. return $user;
  34. }
  35. }
Oczywiście to tylko podgląd ogólnego mechanizmu działania. Taki kod kompletnie nie nadaje się do prawdziwego użytku. Jest za prymitywny, polegnie po 20 minutach użytkownika. Na dobrą sprawę "napełnianie" obiektu danymi z bazy również powinno być zrobione inaczej (przez mechanizm refleksji, który pominie normalne settery), nawet w sumie samo utworzenie obiektu powinno być inaczej zrobione.

Jak już mówiłem... mapowanie danych pomiędzy obiektami, a nieobiektową bazą danych jest trudnym zadaniem. Nawet bardzo trudnym. Skorzystaj z gotowego ORM-a, chociażby po to by zobaczyć jak to powinno wyglądać. Pisałem już wcześniej o Doctrine2 bo jest to póki co jedyny PHP-owski ORM o "słusznej" architekturze (nowość w świecie PHP, ale jest to stare i sprawdzające się rozwiązanie na świecie). A nawet i taki ORM w końcu polegnie przy bardziej "wymyślnych" potrzebach.
Go to the top of the page
+Quote Post
thek
post
Post #38





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




Pomyśl nad tym co chcesz osiągnąć... Jak dla mnie sensowniejsze jest, by funkcja ta zwracała już od razu obiekt klasy User i to od programisty zależy co z tym obiektem dalej będzie robił. Dla mnie w takim wypadku sensownym byłoby takie napisanie konstruktora, by mógł on przyjąć jako parametr liczbe. Wywołanie bezparametrowe utworzy pusty obiekt (czyli wstęp dla tworzenia nowego usera), a z liczbą utworzyło by obiekt uzupełniony danymi usera o takim id lub wyjatek, jeśli ktoś sobie jaja zacznie robić i wpisze id usera, którego nie ma. Pamiętaj, że konstruktor to metoda jak każda inna i parametry może przyjmować, o czym niestety wielu poczatkujących zapomina, traktujac go jako jakąś magię straszną (IMG:style_emoticons/default/wink.gif) Ci którzy "wychowywali się" na C/C++ wiedza jakie cuda można z pomocą konstruktorów robić i dla nich to co jest w php daje tak naprawdę ograniczone możliwości. Sam pamiętam jak kolega obok siedzący zaczął się za bardzo wzorować na typowych i do znalezienia w necie przykładach dla Kohany. Niemal nigdy kontroler w swoim konstruktorze nie przyjmuje parametru. Mój kod miał to w określonych wypadkach i trochę to za dziwne uznawał, do czasu aż mu to się samemu nie spodobało , bo czasem upraszcza pewne rzeczy. Tak jak w tym wypadku, gdzie konstruktor jest jednocześnie inicjalizatorem.
Go to the top of the page
+Quote Post
melkorm
post
Post #39





Grupa: Zarejestrowani
Postów: 1 366
Pomógł: 261
Dołączył: 23.09.2008
Skąd: Bydgoszcz

Ostrzeżenie: (0%)
-----


Jak najbardziej popieram wizję Thek'a,

  1. try
  2. {
  3. $user = new User(666);
  4. // dalsze operacje
  5. }
  6. catch( RecordNotFound $e)
  7. {
  8. // redirect czy stworzenie nowego usera itp
  9. }
  10.  
Go to the top of the page
+Quote Post
Crozin
post
Post #40





Grupa: Zarejestrowani
Postów: 6 476
Pomógł: 1306
Dołączył: 6.08.2006
Skąd: Kraków

Ostrzeżenie: (0%)
-----


@thek, @melkorm: Przy kodzie: $user = new User(123); jest jeden, spory problem. Skąd u licha ten obiekt będzie miał uzyskać dostęp do bazy danych, informacji o tym jak model obiektowy jest odwzorowany w bazie danych itd? Przecież nigdzie nie są one mu przekazywane. W takim razie będzie musiał w swoim wnętrzu skorzystać ze stanu globalnego by się do nich dobrać - chyba nie muszę wam wymieniać wszystkich konsekwencji korzystania z takiego czegoś? Dalej obiekt ten nagle z prostego obiektu typu POPO (PHP-owski odpowiednik POJO) staje się dosyć skomplikowanym obiektem, wykonującym dziesiątki rzeczy (koniecznych do mapowania danych z bazy). Dalej, dlaczego pobieranie po kluczu głównym jest aż tak uprzywilejowane, że jest w ogóle wrzucone w osobne miejsce? Dlaczego pobierając po przykładowo kluczu unikalnym: $userManager->findOneByEmail('abc@def.ghi') mam korzystać z obiektu menadżera, a w przypadku klucza głównego z obiektu encji? Po co tworzyć takie wyjątki?
Go to the top of the page
+Quote Post
rahul
post
Post #41





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


@Crozin - No to takie cos napisalem, czyli nowy obiek utworzyles w metodzie UserManagera po czym go zwracasz. Z tym extends Abstract to jeszcze nie wiem o co be a za czytanie doctrine juz sie zabieram.
Cytat
Pisałem już, że mapowanie danych pomiędzy bazą danych i obiektami jest samo w sobie trudnym zadaniem. Na razie odpuść sobie ćwiczenia w tym "sektorze", skorzystaj z gotowego narzędzia które będzie w ogóle działać, a OOP poćwicz sobie na czymś innym

Moze to mapowanie w sobie jest trudne, ale poki co staram sie zrozumiec gdzie je umiescic i miec jakis zarys na wyglad klas ich podzial na obowiazki. Ciezko cwiczyc praktycznego php bez operacji na danych z bazy a te przyklady z ksiazek czy net'a typu Pies - siadaj, pies daj glos jakos mnie nie duzo ucza. Przypominam ze chce napisac narazie cms ala sklepik i zrozumiec stopniowo OOP.
Dzieki za odpowiedzi i bogate rozwiniecie tematu.
Go to the top of the page
+Quote Post
thek
post
Post #42





Grupa: Moderatorzy
Postów: 4 362
Pomógł: 714
Dołączył: 12.02.2009
Skąd: Jak się położę tak leżę :D




@Crozin: niekoniecznie ze stanu globalnego. Kto mi zabroni tworzyć powiązanie z bazą danych dopiero w określonym momencie? Owszem... Mogę jawnie wstrzyknąć obiekt połączenia do konstruktora, ale mogę też dopiero na tamtym etapie próbować takie połączenie utworzyć na podstawie plików konfiguracyjnych. To JAK to będzie ostatecznie rozwiązane to już raczej "dalszy plan", a my skupiamy się, jak słusznie zauważyłeś, na pewnego rodzaju mapowaniu. A tym samym nas tutaj interesuje logiczna reprezentacja pewnych powiązań, a nie głębsze sięganie już pod kątem implementacji określonych wzorców czy rozwiązań, takich jak wspomniany DI©. To GDZIE i KIEDY zostanie nawiązane połączenie jest teraz akurat mniej istotne. Równie dobrze mogę na poziomie aplikacji nawiązać je i przerzucać pewną strukturę połączenia do bazy jako domyślny parametr wszelkich konstruktorów jak u jawnie. To jest rzecz, którą przemyśleć się powinno na etapie implementacji, a nie diagramów UML ogólnych (IMG:style_emoticons/default/smile.gif) Bo wiadomo, że taki obiekt musi zaistnieć, ale to w jaki sposób, jest już mniej istotne. Teraz najważniejsze jest określić to jak klasy User i UserManager są od siebie zależne, jak współpracują, jakie mają metody. Nie mieszajmy od razu do całości refleksji, która jest przydatna głównie tam, gdzie nie wiemy do końca z czym mamy do czynienia. Jeśli jest inaczej i znamy wszystko od A do Z to po co ruszać małej wydajności kobyłę do czegoś co można rozwiązać prościej. Bo chyba nie zaprzeczysz, że ruszanie tego mechanizmu w większości przypadków jest zwyczajnym marnotrawstwem zasobów.

@rahul: chcesz złapać nieco nieco idei? Najpierw zastanów się nad funkcjonalnościami i tym co się z nimi wiąże. Staraj prześledzić poruszanie po stronie/sklepie i zauważyć mniejsze cegiełki. W końcu zauważysz te najmniejsze, powiązania z większymi i to da Ci pewne spojrzenie na pewne rzeczy obowiązkowe. Gdy siądziesz, głębiej zaczniesz zauważać, że pewne rzeczy są do siebie podobne i są przykładowo szczególnymi przypadkami innych choćby czy mają zbliżone funkcjonalności. Przykład? Artykuł, Post, News... Są pewną odmianą Wpisu. Wszystkie mają pewne wspólne pola i metody. Różnią się jedynie drobnymi szczegółami. Już to daje Ci powód do użycia dziedziczenia lub narzucenia określonych interfejsów. Z biegiem czasu takie spostrzeżenia staną się naturalniejsze. Ja do dziś zanim siądę do kompa siadam z kartką papieru i długopisem rozrysowując i rozpisując sobie wszystko co wpadnie mi do głowy. Wolę spędzić kilka dni na tym i mieć potem po prostu szybkie kodzenie, niż siąść od razu do kodzenia by po kilku dniach przepisywać coś od nowa, bo nie pomyślałem o określonej funkcjonalności. Czasem jest tak, że po fakcie zauważam, iż już gotowe rozwiązanie pozwala mi na pewne zastosowania w nie planowanych sytuacjach. Jest na tyle elastyczne, że mogę je wykorzystać w innym miejscu, lub na jego bazie inny problem rozwiązać prościej. Sam niedawno zrobiłem jedną funkcjonalność w serwisie, która miała być tylko dla zalogowanych. Teraz jednak się okazało, że można ją pchnąć dla niezalogowanych, a już mi szef wspomniał, że to fajny sposób by rozwinąć pod kątem społecznościówki, jako jeden z elementów.
Go to the top of the page
+Quote Post
smentek
post
Post #43





Grupa: Zarejestrowani
Postów: 130
Pomógł: 11
Dołączył: 7.04.2003

Ostrzeżenie: (10%)
X----


Chciał bym się odnieść do paru perełek:

1. Metody magiczne __get(), __set(), __call() etc są ZŁE. Złe jak Adolf Hitler i koniec tematu.

2. Padło zdanie że przy takich metodach jest mniej parsowania (rozumiem ze autor uważa ze jest szybciej). Prawda jest taka że te metody są kilka razy wolniejsze od swoich zwyczajnych odpowiedników. Samo czytanie pliku z kodem zajmuje niewielki ułamek czasu w stosunku do wykonywania kodu + prasowanie idzie jeden raz na Request, wykonywanie może iść wielokrotnie. Tak że może zaoszczędzisz 0.00001s na parsowaniu ale potem tracisz 0.005 s podczas wykonania skryptu.

2. To ze IDE podpowiada ze istnieje metoda __get() i __set() to żaden argument. Programistę interesuje to jakie KONKRETNE metody/zmienne ma obiekt a nie to czy dany obiekt korzysta z magii czy nie. Jeżeli obiekt kożysta z magi to patrz punkt 1.

---
Ok niedopatrzylem i widze ze twoje IDE podpowiada tez zmienne więc tu mnie masz (IMG:style_emoticons/default/smile.gif)
---

3. Parameters bag uzyty w Symfony2 jest bardzo specyficznym obiektem, który zbiera dane z $_REQUEST. $_REQUEST jest w PHP tablicą. To jest wyjątkowa sytuacja więc usprawiedliwia ona wyjątkowe podejście. Nie należy z tego generalizować żadnych wniosków na temat seterów i geterów, magii czy czegokolwiek.

Warto jeszcze dodać że getery i settery dla obiektów typowo biznesowych. Np dla obiektów perzystentnych czyli takich które chcemy zapisać do bazy. W obiektach nie nie biznesowych powinniśmy unikać getterow i setterow.

Ten post edytował smentek 24.08.2011, 20:22:40
Go to the top of the page
+Quote Post
rahul
post
Post #44





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


Ey ziomeczki, a nakierujcie mnie prosze w kwesti napisania funkcji update w takim przypadku :

  1. $userM = new UserManager() ;
  2. $user = $userM->getById(1500);
  3. $user->setName('paradontozaur');
  4. $userM->update($user);
  5.  


Chodzi o to ze niezaleznie od tego czy ustawie jeden parametr typu name , badz kilka jak name, pass, email aby zrobic sobie tylko userManager->update($user) i pyk.
Jak ta funkcja bedzie wiedziala po przekazanym jej obiekcie w ktorych wierszach tabeli zmienic dane a gdzie pozostawic stare ?
Go to the top of the page
+Quote Post
Fifi209
post
Post #45





Grupa: Zarejestrowani
Postów: 4 655
Pomógł: 556
Dołączył: 17.03.2009
Skąd: Katowice

Ostrzeżenie: (0%)
-----


Napisz klasę, która będzie obserwować obiekt, jak się zmienia. Jeżeli się zmieni to wywołaj update.
Go to the top of the page
+Quote Post
rahul
post
Post #46





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


no jo, ale nie bardzo wiem jak (IMG:style_emoticons/default/tongue.gif)
Go to the top of the page
+Quote Post
Noidea
post
Post #47





Grupa: Zarejestrowani
Postów: 226
Pomógł: 61
Dołączył: 20.08.2010

Ostrzeżenie: (0%)
-----


@Fifi209 Moim zdaniem bez sensu. Przy zmianie kilku wartości obiektu User kilka razy wykona się UPDATE. Dodatkowo będą problemy z odtworzeniem słuchaczy obiektu User po deserializacji.

Cytat
Jak ta funkcja bedzie wiedziala po przekazanym jej obiekcie w ktorych wierszach tabeli zmienic dane a gdzie pozostawic stare ?

Nic się nie stanie jak zaktualizujesz stare wartości w bazie danych, tymi samymi starymi wartościami z obiektu $user. Zrób w tej metodzie jedno zapytania aktualizujące wszystkie pola (poza ID)
Go to the top of the page
+Quote Post
rahul
post
Post #48





Grupa: Zarejestrowani
Postów: 71
Pomógł: 0
Dołączył: 5.03.2011

Ostrzeżenie: (0%)
-----


a no, jak tak to bez problemu.


Kontynuujac - Czy majac klase UserManager w momencie zwracania wiecej niz jeden obiekt z tabeli (funkcja findAll() ) powinienm utworzyc zmienna typu np userCollection?
  1. class UserManager {
  2.  
  3. private $db;
  4. private $userCollection = array();
  5.  
  6. public function __construct(Database $db)
  7. {
  8. $this->db = $db;
  9. }
  10.  
  11. public function findById($id)
  12. {
  13. $sql = $this->db->query("SELECT * from users WHERE id= '$id'"); // tutaj miejsce na doctrice w przyszlosci
  14. $data = $sql->fetch(PDO::FETCH_OBJ);
  15. $user = New User();
  16. $user->setName($data->name);
  17. $user->setLastName($data->lastName);
  18. return $user;
  19. }
  20.  
  21. public function findAll()
  22. {
  23. $sql = $this->db->query("SELECT * from users"); // tu tak samo doctine
  24. $data = $sql->fetchAll(PDO::FETCH_OBJ);
  25. foreach ($data as $row)
  26. {
  27. $user = New User();
  28. $user->setName($row->name);
  29. $user->setLastName($row->lastName);
  30. $this->userCollection[] = $user;
  31. }
  32. return $this->userCollection;
  33. }
  34.  
  35. public function create($user)
  36. {
  37. ...
  38. }
  39.  
  40. public function update($user)
  41. {
  42. ...
  43. }
  44.  
  45. public function delete($user)
  46. {
  47. ..
  48. }
  49. }


I czy jakbym przekazywal obiekt User do konstruktora klasy UserManager, czy byloby to w jakis sposob lepsze ?

Ten post edytował rahul 26.08.2011, 22:12:43
Go to the top of the page
+Quote Post
starach
post
Post #49





Grupa: Zarejestrowani
Postów: 999
Pomógł: 30
Dołączył: 14.01.2007
Skąd: wiesz ?

Ostrzeżenie: (0%)
-----


Cytat(rahul @ 26.08.2011, 23:13:56 ) *
a no, jak tak to bez problemu.


Kontynuujac - Czy majac klase UserManager w momencie zwracania wiecej niz jeden obiekt z tabeli (funkcja findAll() ) powinienm utworzyc zmienna typu np userCollection? (...)
Tak albo jako zwykła tablicę, to zależy w sumie od założeń modelu. Możesz też równie dobrze zrobić obiekt który będzie imitował tablicę implementując ArrayAccess.

Cytat(rahul @ 26.08.2011, 23:13:56 ) *
(...)
I czy jakbym przekazywal obiekt User do konstruktora klasy UserManager, czy byloby to w jakis sposob lepsze ?
Po co?


Pobierasz jeden rekord ( np. Jednego użytkownika ) tworzysz nową zmienną User, pakujesz do niej dane i zwracasz. Z wieloma rekordami jest tak samo.
Go to the top of the page
+Quote Post
Sajrox
post
Post #50





Grupa: Zarejestrowani
Postów: 254
Pomógł: 7
Dołączył: 9.10.2007
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Chciałbym poćwiczyć technikę 'Dependency Injection'. Założenia są takie by pobrać użytkownika, przekazać go do klasy Managera i tam zająć się pobieraniem go z bazy itp...

Generalnie mam jedną koncepcję bez samej implementacji klas:
  1. // .. implementacja klas
  2.  
  3. // Wywołanie
  4. $user = new User(1); // tworze obiekt User o podanym id, może być nie istniejące
  5.  
  6. $userManager = new UserManager($user); // tworze Managera uzytkownika
  7. $userData = $userManager->getData(); // Pobiera dane z bazy po id uzytkownika trzymanego w obiekcie User, id musi istnieć w bazie
  8.  
  9. $userManager->changePassword('abc123'); // zmieniam hasło
  10. $userManager->save(); // Zapisuje zmiany
  11. $userDataNew = $userManager->getData(); // Pobieram znowu dane, tym razem zmienione
  12.  
  13. // inny przypadek
  14. $user2 = new User(); // tworze obiekt User o nieistniejącym id
  15. $userManager2->createNew(); // tworze nowego użytkownika z kolejnym id, wywali wyjatek gdyż np. login i hasło są wymagane
  16. $userNewData = $userManager2->getData(); // Pobiera dane z bazy dla nowego usera


W tym kodzie implementacja nie jest ważna, chodzi mi samo wywołanie. czy jest ono sensowne i zgodnie z OOP i 'Dependency Injection'. No i ogólnie czy taki kod ma sens?

Ten post edytował Sajrox 5.09.2011, 11:27:20
Go to the top of the page
+Quote Post
Noidea
post
Post #51





Grupa: Zarejestrowani
Postów: 226
Pomógł: 61
Dołączył: 20.08.2010

Ostrzeżenie: (0%)
-----


1. Nic nie stoi na przeszkodzie, żeby UserManager zarządzał wieloma użytkownikami. Nie musisz tworzyć nowego obiektu dla każdego usera. Jeśli natomiast chcesz tworzyć UserManagera dla każdego użytkownika, to po co ci klasa User. Równie dobrze zamiast:
  1. $userId = 1234;
  2.  
  3. $user = new User($userId); // tworze obiekt User o podanym id, może być nie istniejące
  4. $userManager = new UserManager($user);
  5.  
  6. // Mógłbyś pisać:
  7. $userManager = new UserManager( $userId );

2. W związku z pkt. 1 nie możesz już przekazywać obiektu User w konstruktorze UserManagera. Zamiast tego będziesz musiał poinformować metodę getData() o jakiego użytkownika ci chodzi.
3. Nie wiem czym się u ciebie różni user od userData, ale moim zdaniem jest to zbędne rozgraniczenie

Po oczyszczeniu kodu ze zbędnych instrukcji, zostanie ci pewnie coś w rodzaju:
  1. $userManager = new UserManager($userId);
  2. $userData = $userManager->getData();
  3.  
  4. $userManager->changePassword('abc123');
  5. $userManager->save();
  6. $userDataNew = $userManager->getData();

Jak widzisz jedynymi informacjami jakie przekazujesz tutaj w parametrach jest ID użytkownika i hasło. Jak się pewnie domyślasz, obok DI to to nawet nie stało (IMG:style_emoticons/default/smile.gif)

Dla porównania podaję zalążek kodu wykorzystania (a przynajmniej tego, jak ja to widzę) klasy UserManager, korzystającej z PDO oraz logującej błędy:
  1. <<?php
  2.  
  3. interface ILogger
  4. {
  5. function Log( $message );
  6. }
  7.  
  8. class TxtLogger implements ILogger
  9. {
  10. public function __construct( $filePath )
  11. { /*...*/}
  12.  
  13. public function Log( $message )
  14. { /* Zapisuje wiadomość do pliku ... */ }
  15. }
  16.  
  17. class NullLogger implements ILogger
  18. {
  19. public function Log( $message )
  20. {
  21. return; // ignoruje wiadomość (nie zapisuje jej nigdzie)
  22. }
  23. }
  24.  
  25. class User { /* kontener na dane użytkownika */ }
  26.  
  27. class UserManager
  28. {
  29. private $db;
  30. private $logger;
  31.  
  32. public function __construct( PDO $db, ILogger $logger )
  33. {
  34. $this->db = $db;
  35. $this->logger = $logger;
  36. }
  37.  
  38. public function getDataById( $userId )
  39. {
  40. // Pobierz dane na temat użytkownika z bazy danych.
  41. // Jeśli znaleziono użytkownika o podanym ID, utwórz, wypełnij i zwróć obiekt klasy User
  42. // W przeciwnym wypadku zapisz informację o błędzie przy użyciu loggera i rzuć wyjątek
  43. }
  44. }
  45.  
  46. $mysqlDb = new PDO( "blablabla" );
  47. $userManager = new UserManager( $mysqlDb, new NullLogger() ); // Utworzenie managera użtykowników, korzystającego z bazy MySQL i nie logującego błędów
  48.  
  49. ?>


Go to the top of the page
+Quote Post
Sajrox
post
Post #52





Grupa: Zarejestrowani
Postów: 254
Pomógł: 7
Dołączył: 9.10.2007
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Wydaje mi się że poniższe rozwiązanie nie jest zbyt dobre, mianowicie:
  1. $mysqlDb = new PDO( "blablabla" );
  2. $userManager = new UserManager( $mysqlDb, new NullLogger());


Zawsze gdy chcemy utworzyć instancję klasy 'UserManager' musimy tworzyć obiekt PDO. Klasa 'UserManager' i tak jest przystosowana do pracy z PDO, więc można po prostu obiekt tworzyć już wewnatrz 'UserManager' albo wykorzystać dziedziczenie np. po klasie DbManager

Oto kolejna partia kodu kóra jest wygodna i chyba jako tako obiektowa. User jest tylko kontenerem, Manager zarządza tym kontenerem (gdy User ma id to znaczy że tyczy się nowego usera, gdy nie ma to jest to nowy kontener dla nowego usera)
  1. // tworzymy obiekt User
  2. $user = new User();
  3. $user->id = 1;
  4. $user->name = 'Bob';
  5.  
  6. // tworzymy obiekt managera ktory zarządza użytkownikiem
  7. $userManager = new UserManager(
  8. $user, // domyslnie jest NULL
  9. new DbSqlManager(), // mozna ustawić domyslonie w klasie
  10. new NullLogger() // mozna ustawić domyslonie w klasie
  11. );
  12. $userData = $userManager->getData(); // zwracamy obiekt User wszystkie inne dane uzytkownika o id = 1
  13.  
  14. $userData->name = 'Steve';
  15.  
  16. $userManager->setData($userData); // zmiana danych
  17. $userManager->save(); // zapisuje usera korzystająć z jego id


  1. // Inny przykład
  2. $user = new User();
  3. //$user->id = 1; // bez id wieć teraz obiekt User jest nowym użytkownikiem
  4. $user->name = 'Bob';
  5.  
  6. // manager nie może robic edycje i usuwanie gdyż obiekt User nie ma id więc jest nowym oniektem a nie istniejącym dla danego usera
  7. $userManager = new UserManager(
  8. $user,
  9. new DbSqlManager(),
  10. new NullLogger()
  11. );
  12.  
  13. $user = $userManager->getUser(); // Zwraca błąd
  14. $userManager->saveNew(); // Doda nowego o imieniu Bob


Ten post edytował Sajrox 7.09.2011, 10:18:19
Go to the top of the page
+Quote Post
Noidea
post
Post #53





Grupa: Zarejestrowani
Postów: 226
Pomógł: 61
Dołączył: 20.08.2010

Ostrzeżenie: (0%)
-----


Cytat
Zawsze gdy chcemy utworzyć instancję klasy 'UserManager' musimy tworzyć obiekt PDO.

Nie musimy. Obiekt PDO można utworzyć raz i przekazywać go w parametrze konstruktora do każdego nowo tworzonego obiektu UserManager. Stosowanie Dependency Injection Container-a jeszcze bardziej upraszcza sprawę. Konfigurujesz w nim na początku sposób, w jaki mają być tworzone obiekty UserManager, a następnie tworzysz je wywołując po prostu jedną metodę:
  1. $userManager1 = $container->resolve( "UserManager" );
  2. $userManager2 = $contanier->resolve( "UserManager" );

Zapis będzie się różnił w zależności od DIC-a, który wybierzesz, ale zasada działania pozostaje niezmienna.
Dzięki temu jeśli kiedyś stwierdzisz, że potrzebujesz przekazywać do konstruktora UserManagera jeszcze jeden parametr, to zmiany wprowadzasz w jednym miejscu kodu, a nie wszędzie tam, gdzie korzystałeś z obiektów tej klasy.

Cytat
  1. $user = new User();
  2. $user->id = 1;
  3. $user->name = 'Bob';

Jeżeli chcesz stosować taki zapis (pola publiczne klasy), to ok, ale wymienię kilka wad tej metody:
- Nie możesz w ten sposób tworzyć właściwości tylko do odczytu
- Nie możesz wykonywać dodatkowych akcji podczas ustawiania wartości pola (np. odpalenie zdarzenia (rzadko spotykane w PHP) czy rzucenie wyjątku)
- Jeśli z powyższych powodów będziesz chciał zamienić część pól na gettery i settery, to skończysz z nieusystematyzowanym interfejsem. Zawsze będziesz musiał się zastanawiać, czy do name mam się odwoływać jak do zwykłego pola klasy, czy też napisałem już dla niego gettera
- Każda zmiana pola klasy na gettera/settera(akcesora) będzie powodowała konieczność sprawdzenia pozostałych plików projektu i poprawienia odwołań do tego pola. Jeśli od razu będziesz stosował akcesory, to tego problemu nie będzie.

Ręczne pisanie akcesorów jest upierdliwe, ale jeśli korzystasz z jakiegoś bardziej zaawansowanego edytora, to będzie on potrafił zrobić to za ciebie. Np. w Netbeansie robi się to przy użyciu skrótu Alt+Insert

Co do przekazywania obiektu User w konstruktorze UserManagera: Jeśli jest ci to potrzebne, to ok. Tyle że jeżeli będziesz chciał używać tego managera również do operacji pobierania kolekcji użytkowników, będzie to wyglądało dziwnie
  1. // Pobranie kolekcji 5 obiektów User, reprezentujących ostatnio zarejestrowanych użytkowników
  2. $user = new User();
  3. $userManager = new UserManager( $user, /* ...*/ );
  4. $latestRegisteredUsers = $userManager->getLatestRegisteredUsers( 5 );

Dla osoby, która pierwszy raz ma styczność z twoim projektem linijka 3 jest zrozumiała. Natomiast 1 i 2 mogą wprowadzić konsternację (po co pusty obiekt User do pobrania ostatnio zarejestrowanych użytkowników?)
Go to the top of the page
+Quote Post

3 Stron V   1 2 3 >
Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 16.10.2025 - 23:50