Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: prawidlowe OOP , struktura klasy
Forum PHP.pl > Forum > PHP > Object-oriented programming
Stron: 1, 2
Noidea
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 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. ?>


Sajrox
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
Noidea
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?)
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.