Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] co powinna zawierac klasa?
Forum PHP.pl > Forum > Przedszkole
miczops
witam, znalazlem na forum taki temat: Temat: Klasa PHP system artykulow

nie ma tam jednak wytlumaczenia czemu w klasie Article nie moze byc metody deleteArticle ? w takim razie gdzie ona ma byc? jest napisane, ze w Article_Model, ale jakby wtedy miala wygladac klasa Article? jest cos, ze informacje o tytule, tresci itp, ale jakby to mialo wygladac?
lukaskolista
generalnie klasa powinna miec to, czego potrzebujesz do operacji na obiektach tej klasy. Jezeli potrzebujesz miec mozliwosc usuniecia artykulu jako obiektu, to niby czemu nie? Pamietaj, ze kazdy ma nieco inne podejscie do programowania, jednym cos pasuje a innym nie. Juz bardziej akrykul nie powinien miec mozliwosci laczenia sie z baza, polaczenie z baza z reguly (chyba we wszystkich normalnych projektach) jest osobnym obiektem

metody klasy article
create
edit
delete

sa jak najbardziej w porzadku.

Co do modelu: jest to wymysl MVC ktorego w zadnym wypadku nie musisz implementowac.
bastard13
Klasa powinna zawierać wszystko co jest niezbędne do operacji na niej.
Programowanie obiektowe ma to do siebie, że warto (na początku, w trakcie nauki) zadawać sobie pytanie, co klasa musi mieć np. klasa Artykuł?
Pasowałoby, żeby miała wartości (atrybuty) tytuł i tekst. W dobrym zwyczaju jest tworzyć atrybuty jako protected bądź private i dodawać odpowiednie settery i gettery (w zależności od potrzeb).
Artykuł powinno się móc stworzyć, zniszczyć i edytować. To wszystko są metody.
Jednak, tak jak napisał lukaskolista samo połączenie z bazą to już powinna być inna klasa (czasopismo, w którym jest artykuł, to nie jest już część artykułu:)
Oczywiście to tylko bardzo krótki wstęp, ale tak mniej więcej to wygląda.
miczops
dzieki za odpowiedzi. a jakbym to mial zapisac w tej klasie te atrybuty tytul i tekst? i czy cos takiego jak setter jest potrzebne, jesli bede operowal tylko na danych z bazy?
bastard13
Nic nie jest wymagane, to tylko sugestie.
Klasa Article posłużyła jedynie za przykład:
  1. class Article
  2. {
  3. protected $_title;
  4. protected $_content;
  5.  
  6. public function setContent($content)
  7. {
  8. $this->_content = $content;
  9. return $this;
  10. }
  11. public function getContent()
  12. {
  13. return $this->_content;
  14. }
  15.  
  16. public function setTitle($title)
  17. {
  18. $this->_title= $title;
  19. return $this;
  20. }
  21. public function getTitle()
  22. {
  23. return $this->_title;
  24. }
  25.  
  26. static public function factory()
  27. {
  28. return new self();
  29. }
  30. }


Oczywiście dla pobierania artykułu z bazy danych wygląd i budowa klasy będzie inna, ale myślenie jest podobne.
miczops
dzieki smile.gif

a mozesz mi jeszcze powiedziec jakie zastosowanie tutaj maja te settery? bo get to wiem, ale dajmy ze mam bloga z artykulami i w jakiej sytuacji moge uzyc setterow? i co robi ta funkcja factory? i czemu wlasciwie np w GetTitle nie ma zrobionego pobierania z bazy?
bastard13
To był tylko przykład.
Nie sugeruj się tym co napisałem, bo to nie jest klasa pobierająca cokolwiek z bazy, tylko klasa pokazująca budowę.
W twoim przypadku wyglądałoby to np. tak:
  1. class Article
  2. {
  3. protected $_title = '';
  4. protected $_content = '';
  5. protected $_id = null;
  6.  
  7. public function __construct($id = null)
  8. {
  9. if ($id !== null)
  10. //jeżeli zostało przekazane id tzn. że trzeba pobrać z bazy, więc tutaj w tym momencie byłoby zapytanie typu:
  11. //select title,id,content from article where id=$id
  12. //oraz przypisanie odpowiednich wartości do odpowiednich parametrów klasy
  13. }
  14.  
  15. public function setContent($content)
  16. {
  17. $this->_content = $content;
  18. return $this;
  19. }
  20. public function getContent()
  21. {
  22. return $this->_content;
  23. }
  24.  
  25. public function setTitle($title)
  26. {
  27. $this->_title= $title;
  28. return $this;
  29. }
  30. public function getTitle()
  31. {
  32. return $this->_title;
  33. }
  34.  
  35. static public function factory($id = null)
  36. {
  37. return new self($id);
  38. }
  39.  
  40. public function save()
  41. {
  42. if($this->_id === null)
  43. //nowy artykuł więc dodajemy do bazy
  44. else
  45. //skoro jest id tzn. że updatujemy rekord w bazie
  46.  
  47. return boolean; //zwracanie true lub false
  48. }
  49.  
  50. public function delete()
  51. {
  52. if($this->_id === null)
  53. return false; //nowy artykuł więc nie ma co usuwać, czyli nie usunięto, zwracamy false
  54. else
  55. //skoro jest id to delete elementu
  56.  
  57. return boolean; //zwracanie true lub false
  58. }
  59.  
  60. }


I teraz masz tak:
update:
  1. //update elementu o id 1, ustawianie title = tytul, content = content
  2. Article::factory(1)
  3. ->setTitle('tytul')
  4. ->setContent('content')
  5. ->save();

usuwanie elementu o id 1
  1. Article::factory(1)->delete();

nowy:
  1. Article::factory()
  2. ->setTitle('tytul')
  3. ->setContent('content')
  4. ->save();


Factory po to, żeby nie trzeba było robić tak:
  1. $article = new Article;
  2. $article->setTitle('tytul')
  3. ->setContent('content')
  4. ->save();


Jest to jeden z wzorców projektowania, o których warto poczytaćsmile.gif
miczops
o super, wielkie dzieki dobry czlowieku smile.gif a jaki to jest wzorzec? MVC?
jeszcze mam kilka pytan tongue.gif wzialem ta klase i przykladowo zrobilem tak:

  1. class Article
  2. {
  3. protected $_title = '';
  4. protected $_content = '';
  5. protected $_id = null;
  6.  
  7. public function __construct($id = null)
  8. {
  9. if ($id !== null) {
  10. $pdo = $pdo->query(select * from article where id = $id);
  11. return $pdo;
  12. }
  13. }
  14. // construct zawsze sie wykonuje przy odwolaniu do klasy?
  15. public function setContent($content)
  16. {
  17. $this->_content = $content;
  18. return $this;
  19. }
  20. public function getContent()
  21. {
  22. return $this->_content;
  23. }
  24.  
  25. public function setTitle($title)
  26. {
  27. $this->_title= $title;
  28. return $this;
  29. }
  30. public function getTitle()
  31. {
  32. return $this->_title;
  33. }
  34.  
  35. static public function factory($id = null)
  36. {
  37. return new self($id);
  38. }
  39.  
  40. public function save()
  41. {
  42. if($this->_id === null) {
  43. $pdo->prepare(insert into ) itd
  44. /bind value itd
  45.  
  46. else
  47. $pdo->prepare (update itd
  48.  
  49. return boolean; //true zwraca jesli sie wykona, a false jesli nie? tylko skad ta funkcja wie co zrobilo $pdo?
  50. }
  51.  
  52. public function delete()
  53. {
  54. if($this->_id === null)
  55. return false; //nowy artykuł więc nie ma co usuwać, czyli nie usunięto, zwracamy false
  56. else
  57. //skoro jest id to delete elementu
  58.  
  59. return boolean; //zwracanie true lub false
  60. }
  61.  
  62. }


laczenie z baza mam w innej klasie, wiec jak to zrobic w tej? a moze po prostu ta powinna rozszerzac klase np CONNECT i zrobic:
class Article extends Connect ?

i jeszcze


protected $_title = '';
protected $_content = '';
protected $_id = null;

+
public function getContent()
{
return $this->_content;
}

nie do konca kapuje jak to dziala. najpierw je deklarujemy jako protected, czyli sa widoczne tylko w tej klasie, potem jak mamy funkcje ktora zwraca Content to zwracamy _content, ale skad ta klasa wie, ze to akurat opis artykulu?


pozdrawiam i jeszcze raz wielkie dzieki za pomoc
bastard13
1) To nie MVC:) to po prostu OOP:)
2) Połączenie zrealizuj jako Singleton (kolejny DP:) . Nie rozszerzaj klasy Article o to połączenie, bo przecież połączenie z bazą nie ma nic wspólnego z artykułem.
Możesz to zrealizować np. tak:
  1. class DbConnection
  2. {
  3. protected $_connection;
  4. static protected $_instance = null;
  5. static public function getInstance($connection = null)
  6. {
  7. if(self::$_instance === null)
  8. new self($connection);
  9. return self::$_instance;
  10. }
  11. protected __contstruct($connection)
  12. {
  13. $this->_connection = $connection;
  14. }
  15. public function getConnection()
  16. {
  17. return $this->_connection;
  18. }
  19. }

Teraz, żeby pobrać połączenie z bazą musisz wywołać DbConnection::getInstance()->getConnection() i za każdym razem jest to, to samo połączenie.
Oczywiści najpierw musisz je zainicjalizować, czyli DbConnection::getInstance($connection).
Możesz również nawiązywać połączenie w konstruktorze, wtedy nie będzie potrzebne przekazywanie parametru/parametrów za pierwszym razem.
Jest to oczywiście bardzo luźna podpowiedź, a nie dokładna implementacja, ale powinno to wyglądać podobnie.

3) Wszystkie atrybuty powinny być (zazwyczaj) protected bądź private, a odwołanie do nich powinno odbywać się za pomocą getterów i setterów.
Co do tego skąd klasa wie, że to treść artykułu, to przy pobieraniu danych z bazy musisz ustawić wszystkim atrybutom odpowiednie wartości pobrane z bazy.
miczops
dzieki, dzieki, ale jeszcze kolejna prosba wink.gif chce uzywac PDO do laczenia, wiec jakby to ustawienie atrybutow mialo wygladac? mam sobie baze no i tam niech bedzie tylko to TITLE i CONTENT, no i jak to teraz polaczyc z tym co mi tam wyzej napisales? smile.gif tak jak ja zaczalem pisac, czy jakos inaczej? bo rozumiem troche jak to dziala, ale jakos nie moge sobie wyobrazic calego dzialania bez tej bazy.

bo robie np tak jak napisales:
  1. 1.
  2. Article::factory()
  3. ->setTitle('tytul')
  4. ->setContent('content')
  5. ->save();


wiec wskakujemy do klasy i tutaj sie wykonuje to __construct i tam jak ten select wlasnie wyglada, bo nie wiem jak polaczyc te atrybuty? no i wchodzimy do settera i tam jest
  1. $this->_title= $title;
  2. return $this;

czyli by wychodzilo, ze tej zmiennej protected _title przypisujemy to co przeslalismy, czyli $title, ale co nam to daje? jakos bez calego polaczenia z baza nie moge tego pojac, bo tu wychodzi, ze zwracamy to samo co wyslalismy tongue.gif

jeszcze raz wielkie dzieki, ze chce Ci sie poswiecac czas na takie cos smile.gif
lukaskolista
setTitle() jest po to, zeby ustawic wlasciwosc _title obiektu i pozniej zapisac go do bazy za pomoca save()

przykladowy zapis moze wygladac tak

  1. public function save() {
  2. if (isset($this->_id)) {
  3. mysql_query("UPDATE articles SET title='".$this->_title."' WHERE id = ".(int)$this->_id);
  4. } else {
  5. mysql_query("INSERT INTO articles (title) VALEUS ('".$this->_title."')");
  6. }
miczops
dzieki wielkie smile.gif

a jak teraz wyglada pobieranie artykulow, zeby je wyswietlic na stronie glownej, a potem zrobic jeszcze linki do wyswietlenia ich?


myslalem nad czym w stylu

  1. public function showIndex(){
  2. $index=(select * from articles);
  3. }


ale Bastard cos wspomnial, ze w contruktorze to by mozna, wiec tak jak pisalem pare postow wczesniej to jest ok? a jak sie potem do tego odwolowac?

dzieki wielkie za pomoc
Potter125
to już prędzej w klasie musiałbyś zmienić np:
  1. public function __construct($id = null)
  2. {
  3. if ($id !== null) {
  4.  
  5. $pdo = $pdo->query(select * from article where id = $id);
  6.  
  7. } else {
  8.  
  9. $pdo = $pdo->query(select * from article);
  10.  
  11. }
  12.  
  13. return $pdo;
  14.  
  15. }


i w tym wypadku po prostu, jeśli chciałbyś wylistować wszystkie artykuły, to nie wywołujesz save
miczops
dzieki, a jak sie do tego wtedy odwolac, zeby fetchem pobierac?

  1. while($post = Article::factory()->fetch()) {
  2. ?>
  3. <a href=<?php echo $post['id']; ?> > <?php echo $post['title']; ?> </a>
  4. <?php echo $post['content'];
  5. }

?
to id tez pobierze? niestety nie mam teraz jak sprawdzic tego, bede dopiero popoludniu w domu, ale poki co sobie czytam i robie teorie:)


pomoze ktos jeszcze? wink.gif chociazby jakims przykladem
Crozin
Trochę popsuję zabawę... wink.gif Na początek spróbuj zapomnieć o tym co przeczytałeś powyżej, bo ilość fatalnych praktyk czy zapisów wręcz wypaczających podstawowe założenia OOP jest tam ogromna.

1. Chyba najbardziej elementarna zasada OOP - [url=http://en.wikipedia.org/wiki/Single_responsibility_principle]zasada pojedynczej odpowiedzialności (swoją drogą już chyba sety raz wrzucam ten link na tym forum). Jeśli to spieprzysz to z góry spieprzyłeś cały projekt. Zastanów się czy widziałeś kiedyś artykuł (kartkę papieru z tekstem) który jest w stanie sam się utworzyć, sam się zniszczyć i do tego prezentować sobą jakieś informacje? Ja nie, Ty pewnie też. Wszystko dlatego, że artykuł jedyne co robi to reprezentuje jakąś informację, natomiast za jego tworzenie odpowiedzialna jest drukarka, która wykorzystuje czyste (nie wypełnione informacjami) kartki. Nawet niszczenie to często zadanie innej maszyny - niszczarki albo Twoich rąk. Tak samo jest tutaj. Article jedyne co robi to reprezentuje dane. Jakiś ArticleManager odpowiedzialny jest za utrwalanie i usuwanie owych artykułów ze źródła (np. bazy danych). Możesz mieć jeszcze osobny obiekt ArticleRepository odpowiedzalny jedynie za zwracanie danych ze źródła.

2. OOP to jak sama nazwa wskazuje programowanie obiektowe, a klasa jest w nim jedynie złem koniecznym i w miarę możliwości powinieneś unikać wszystkiego co jest z nią bezpośrednio związane. Dotyczy to m.in. właściwości i metod statycznych, z których prawdę mówiąc nie trzeba zbyt często korzystać. Na pewno nie dla czegoś takiego jak Article::factory() co jest jedynie obejściem ułomności PHP (który nie wspiera [tutaj nazwa czegoś takiego: new Article()->setTitle('abc') ale wypadło mi to z głowy]) w dodatku robi to jeszcze w brzydki sposób bo sugeruje, że metoda ta jest fabryką (google: factory pattern) którą nie jest.

3. Singleton to struktura mająca zapewnić istnienie co najwyżej jednego obiektu danej klasy, a nie obejście problemu komunikowania się różnych obiektów. Swoją drogą przecież połączenie z bazą danych to wręcz książkowy przykład gdzie tworzy się 1, 2, 3 obiekty danej klasy.

4. Swoją drogą to co tutaj robisz to nic innego jak ORM. I na tym etapie swojej zabawy z OOP daruj sobie pisanie własnego - nie masz po prostu możliwości zrobienia tego chociażby w miarę dobrze, a jest to w przypadku aplikacji webowych jeden z filarów aplikacji. Słaby ORM będzie Cie prześladować do końca... W PHP nie masz zbyt dużego wyboru. Osobiście proponuję Doctrine2 - trochę mu nadal brakuje, ale jako jeden z nielicznych obrał dobrą, sprawdzoną już gdzie indziej architekturę.

5. PHP ma co prawda bardzo słabo rozpowszechnione i jeszcze niezbyt dobrze ugruntowane konwencje pisania kodu, ale jakieś tam ma, więc się do nich stosuj. Czyli wywal te "_" sprzed nazw właściwości niepublicznych.

6. Tutaj w każdym przypadku powinieneś dla właściwości wykorzystać modyfikator private. Pamiętaj o tym, że protected jednak wchodzi w pewnym stopniu w publiczny interfejs obiektu. Każdy może przecież rozszerzyć Twoją klasę o swoją, która będzie miała dostęp do tych składowych, a raczej nie powinna - od tego są gettery / settery tutaj.
miczops
dzieki za wyklad smile.gif

a z czego konkretnie sie polecasz uczyc? bo jak szukalem po googlach to roznie znajdowalo i teraz nie wiem o co sie zaczepic. najlepszy bylby jakis prosty kurs w przykladach, ale nie takie jak na wikibooks, bo ciezko to zrozumiec, a potem zastosowac w swoim projekcie
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.