Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

 
Reply to this topicStart new topic
> Początki z programowaniem obiektowym - klasa artykuł, Proszę o opinie sugestie
czarek1986
post 24.08.2009, 23:50:13
Post #1





Grupa: Zarejestrowani
Postów: 72
Pomógł: 0
Dołączył: 15.09.2008

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


Witam

Od jakiegoś czasu interesuje się programowaniem obiektowym, ale od niedawna zdecydowałem się stworzyć coś własnego. Będzie to mój pierwszy obiektowy (przynajmniej w części) CMS. chciałbym przedstawić wam klasę artykułu do oceny. Prosze o konstruktywną krytykę smile.gif

  1. <?php
  2.  
  3. class Artykul {
  4.  
  5. //zawiera unikalny numer identyfikujący artykuł w bazie danych
  6. private $id;
  7. //zawiera nazwę autora tworzacego artykuł
  8. private $autor;
  9. //zawiera nazwę kategorii do której przyporządkowany jest artykuł
  10. private $kategoria;
  11. //zaiwera tytuł artykułu
  12. private $tytul;
  13. //zawiera wstępny tekst artykułu
  14. private $naglowek;
  15. //zawiera główną treść artykułu
  16. private $tekst_artykulu;
  17. //zawiera datę utworzenia artykułu !!Unixowy znacznik czasu
  18. private $utworzony;
  19. //zawiera datę ostatniej modyfikacji artykułu !!Unixowy znacznik czasu
  20. private $zmodyfikowany;
  21. //zawiera datę ostatniej publikacji artykułu !!Unixowy znacznik czasu
  22. private $opublikowany;
  23. //określa czy artykuł jest nowo utworzony, czy został wczytany z bazy danych
  24. private $new;
  25.  
  26.  
  27.  
  28. public function __construct($id=NULL)
  29. {
  30. if($id)
  31. {
  32. $this->id_art = $id;
  33. $db = Database::GetInstance();
  34. $sql = "SELECT *
  35. FROM j_artykuly
  36. WHERE id = $id";
  37.  
  38. $art = $db->select($sql);
  39.  
  40. if(!$art)
  41. throw new Exception('Wybrany artykuł nie istnieje');
  42.  
  43. $this->new = false;
  44. $this->set($art[0]);
  45.  
  46. }
  47. else
  48. $this->new = true;
  49.  
  50. }
  51.  
  52. /**
  53. * Metoda zwraca wartość jednego wybranego pola klasy
  54. *
  55. * @param name - nazwa pola w klasie, której wartość chcemy uzyskać
  56. **/
  57.  
  58. public function getOne($name)
  59. {
  60. if(property_exists(get_Class($this), $name))
  61. return $this->$name;
  62. else
  63. throw new Exception('Klasa '.get_class($this).' nie posiada pola '.$name);
  64. }
  65.  
  66. /**
  67. *
  68. * Metoda zwraca wartości wszystkich pól klasy
  69. *
  70. * @return tablica z danymi wszystkich pól;
  71. *
  72. **/
  73.  
  74. public function getAll()
  75. {
  76.  
  77. $arData = array(
  78. 'id' => $this->id,
  79. 'autor' => $this->autor,
  80. 'kategoria' => $this->kategoria,
  81. 'tytul' => $this->tytul,
  82. 'naglowek' => $this->naglowek,
  83. 'tekst_artykulu' => $this->tekst_artykulu,
  84. 'utworzony' => $this->utworzony,
  85. 'zmodyfikowany' => $this->zmodyfikowany,
  86. 'opublikowany' => $this->opublikowany,
  87. );
  88.  
  89. return $arData;
  90. }
  91.  
  92.  
  93. /**
  94. *
  95. * Metoda służy do ustawienia wartości pól w klasie
  96. *
  97. [email="*@Param"]*@Param[/email] arData- tablica przechowująca nazwy pól i odpowiadające im wartości
  98. *
  99. **/
  100.  
  101. public function set(array $arData)
  102. {
  103. foreach($arData as $key => $value)
  104. {
  105. if($key == 'id' && $this->new)
  106. throw new Exception("Wartość pola 'id' może być nadana tylko automatycznie");
  107.  
  108. if(property_exists(get_Class($this), $key))
  109. {
  110. $this->$key = $value;
  111. }
  112. else
  113. throw new Exception('Klasa '.get_class($this).' nie posiada pola '.$key);
  114. }
  115. }
  116.  
  117.  
  118.  
  119. /**
  120. *
  121. * Metoda Tworząca artykuł w bazie danych
  122. *
  123. **/
  124.  
  125. public function createArt()
  126. {
  127. if($this->new)
  128. {
  129. $this->checkRequiredData();
  130.  
  131. $db = Database::getInstance();
  132. if($db->Insert('j_artykuly', $this->getAll()) > 0);
  133. return true;
  134. }
  135.  
  136. throw new Exception('Bierzący artykuł już istnieje w bazie danych. Można go tylko zaktualizować');
  137. }
  138.  
  139.  
  140. /**
  141. *
  142. * Metoda aktualizująca dane artykułu w bazie danych
  143. *
  144. **/
  145.  
  146. public function updateArt()
  147. {
  148. if(!$this->new)
  149. {
  150. $this->checkRequiredData();
  151.  
  152. $db = Database::getInstance();
  153. $arConditions['id']=$this->id;
  154. if($db->Update('j_artykuly', $this->getAll(), $arConditions) > 0);
  155. return true;
  156. }
  157.  
  158. throw new Exception('Musisz najpierw utworzyć artykuł w bazie danych aby móc go edytować');
  159. }
  160.  
  161.  
  162. /**
  163. *
  164. * Metoda usuwająca artykuł z bazy danych
  165. *
  166. **/
  167.  
  168. public function delArt()
  169. {
  170. if(!$this->new)
  171. {
  172. $this->checkRequiredData();
  173.  
  174. $db = Database::getInstance();
  175. $arWhere = array("id = ".$this->id);
  176. if($db->delete('j_artykuly', $arWhere) > 0)
  177. return true;
  178. }
  179.  
  180. throw new Exception('Nie można usunąć bierzącego artykułu, ponieważ nie został jeszcze zapisany w bazie danych.');
  181. }
  182.  
  183.  
  184. /**
  185. *
  186. * Metoda sprawdzająca czy pola, które nie mogą być puste w bazie danych, są wypełnione danymi
  187. *
  188. **/
  189.  
  190. private function checkRequiredData()
  191. {
  192. $arData = array();
  193. $arData = $this->getAll();
  194. $arEmpty = array();
  195. foreach($arData as $key => $value)
  196. {
  197. if($key=='autor' || $key=='kategoria' || $key=='tytul' || $key=='naglowek' || $key=='utworzony')
  198. {
  199. if(!$value)
  200. $arEmpty[]=$key;
  201. }
  202. }
  203.  
  204. if(count($arEmpty) > 0)
  205. {
  206. $empty = implode(', ', $arEmpty);
  207. throw new Exception('Wymagane pola '.$empty.' są puste.');
  208. }
  209.  
  210. return true;
  211. }
  212.  
  213.  
  214. }
  215.  
  216. ?>


Ten post edytował erix 25.08.2009, 11:26:21
Powód edycji: [erix] przeniosłem
Go to the top of the page
+Quote Post
golaod
post 25.08.2009, 08:59:16
Post #2





Grupa: Zarejestrowani
Postów: 419
Pomógł: 42
Dołączył: 12.08.2008
Skąd: Wrocław

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


Bezsensowna sprawa jak dla mnie. Po pierwsze gdzie tu przemyślenie i trzymanie się jednego sposobu pisania metod ? Skoro getOne w ładny sposób czyta czy istnieje zmienna którą ktoś podał w parametrze i ją zwraca to w getAll powinna pętle przechodzić po wszystkich zmiennych klasowych i je dodawać do tablicy zamiast ręcznie rozpisujesz - podstawa to konsekwencja. Po drugie co to jest za klasa ? to kontroler, model, jakieś pudełko czy co ? Rzucanie wyjątkami na lewo i prawo jest trochę dziwne w tym wypadku. Moim zdaniem to powinno służyć tylko do wywalania krytycznych błędów lub czegoś nie do obsłużenia. W przypadku braku zmiennej coś takiego wyrzucać ? Poza tym klasa ma możliwość dodania artykułu pod warunkiem, że przy instancjonowaniu podamy produkt już ISTNIEJĄCY. A jak baza jest pusta to nie dodamy produktu bo się nam obiekt nie utworzy ? Można by się jeszcze poczepiać tylko brakuje mi czasu.
Go to the top of the page
+Quote Post
czarek1986
post 25.08.2009, 09:08:31
Post #3





Grupa: Zarejestrowani
Postów: 72
Pomógł: 0
Dołączył: 15.09.2008

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


Cytat
Poza tym klasa ma możliwość dodania artykułu pod warunkiem, że przy instancjonowaniu podamy produkt już ISTNIEJĄCY. A jak baza jest pusta to nie dodamy produktu bo się nam obiekt nie utworzy ?


Mozna dodawać także i nowe jeszcze nie zapisane do bazy artykuły. Do tego służy metoda CreateArt, która wykona się tylko jeśli wartość pola "new" jest równa true. Jest ono ustawiane własnie podczas tworzenia obiektu w konstruktorze. Jeśli podamy w nim id to obiekt bedzie utworzony na podstawie danych z bazy, a jeśli nie to bedzioe oznaczone własnie jako nowy.

Co do nadmiernych wyjątków, myslisz, że lepiej będzie zwracać po prostu false i dopiero przy uzywaniu takiego obiektu i zwróceniu false odpowiednio wyświetlić komunikat lub wyrzucić wyjątek?

Ten post edytował czarek1986 25.08.2009, 09:10:36
Go to the top of the page
+Quote Post
thek
post 25.08.2009, 10:01:49
Post #4





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




A po co dodatkowy parametr new? ID w zupełności go zastępuje smile.gif W końcu jeśli jest tam NULL, to spełnia on tę samą rolę. Sprawdzasz więc jedynie jaką wartość ma ID i w razie czego podejmujesz decyzję czy robić UPDATE czy INSERT w bazie. To sprawia, że createArt i updateArt możesz zastąpić jedną metodą. Konstruktor w zasadzie działałby podobnie. Brak id -> nowy z wartościami domyślnymi, prawidłowe id -> pobiera artykuł, nieprawidłowe id -> nowy + error. Kwestia funkcji do wyświetlania wszystkiego jest tak naprawdę sporna. Można użyć funkcji getOne, ale używanie funkcji w funkcji to zawsze minimalny narzut czasowy przy wykonywaniu. Więc patrząc od strony wydajności odwołanie się prosto do obiektu pozwala na ominięcie tworzenia zmiennych tymczasowych, odwołania do funkcji, powrotu do funkcji macierzystej, niszczenie zmiennych tymczasowych na stosie itp. Nie jest więc takie głupie jak się może wydawać bo oszczędza nam zarówno czas jak i pamięć serwera. Poza tym popatrz na getOne... Wywołujesz w niej za każdym razem funkcje i warunki. To spowalniałoby getAll za każdym razem.
Zastanawiałbym się także nad kategoria i tagi. Wszystko zależnie od tego jak masz zamiar rozwiązać to od strony bazy. Do przemyślenia jest bowiem choćby to, czy artykuł może być dodany do jednej, czy wielu kategorii. Bo jeśli do wielu to musisz nieco inaczej zapytania popisać. To samo tyczyło by ewentualnego dodania do klasy zmiennej dotyczącej tagów.


--------------------
Najpierw był manual... Jeśli tam nie zawarto słów mądrości to zapytaj wszechwiedzącego Google zadając mu własciwe pytania. A jeśli i on milczy to Twój problem nie istnieje :D
Go to the top of the page
+Quote Post
czarek1986
post 25.08.2009, 10:17:22
Post #5





Grupa: Zarejestrowani
Postów: 72
Pomógł: 0
Dołączył: 15.09.2008

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


Czyli widzę ze zdania podzielone sa co do metody pobierającej wszystkie pola obiektu smile.gif Na razie zostawie ją tak jak jest bo bardziej przemawia do mnie argument, że jest ona szybsza niż jakby miałą wykonywać jeszcze szereg dodatkowych funckji smile.gif

Co do tej zmiennej new to rzeczywiscie mozna to wywalić i zrobić sprawdzanie za pomocą id. Tak zrobie i dzieki za radę. 

A jak z tymi wyjątkami? Nie powinienem umieszczać ich wewnątrz klasy?

Go to the top of the page
+Quote Post
thek
post 25.08.2009, 10:38:15
Post #6





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




Co do wyjątków zdania są podzielone. Puryści uważają, że zostały one stworzone do obsługi błędów i tylko tak je trzeba stosować. Inni używają jak leci, w tym do przekazywania informacji na stronie. Jest to więc tak naprawdę osobista preferencja. Ja osobiście bliższy jestem pierwszej grupie. Informacja o błędach powinna jak najmniej mówić userowi o strukturze serwisu, jego bazach itp, bo to ułatwia ewentualny atak. I dlatego obsługa błędów powinna być używana tylko w miejscach wrażliwych na wystąpienie błędu, by nie dopuścić do sytuacji jaką opisałem w zdaniu poprzednim. W kodzie, który jest pewny można sobie wyjątki darować, bo to w końcu dodatkowa funkcja sprawdzająca efekty wykonywania skryptu i w minimalny sposób go spowalnia.

Ten post edytował thek 25.08.2009, 10:39:23


--------------------
Najpierw był manual... Jeśli tam nie zawarto słów mądrości to zapytaj wszechwiedzącego Google zadając mu własciwe pytania. A jeśli i on milczy to Twój problem nie istnieje :D
Go to the top of the page
+Quote Post
czarek1986
post 25.08.2009, 20:49:55
Post #7





Grupa: Zarejestrowani
Postów: 72
Pomógł: 0
Dołączył: 15.09.2008

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


Troszeczkę przerobniłem moją klasę, według porad oraz własnych pomysłow. Teraz wyszło mi coś takiego.
  1.  
  2. class Artykul {
  3.  
  4. //zawiera unikalny numer identyfikujący artykuł w bazie danych
  5. protected $id;
  6. //zawiera nazwę autora tworzacego artykuł
  7. protected $autor;
  8. //zawiera nazwę kategorii do której przyporządkowany jest artykuł
  9. protected $kategoria;
  10. //zaiwera tytuł artykułu
  11. protected $tytul;
  12. //zawiera wstępny tekst artykułu
  13. protected $naglowek;
  14. //zawiera główną treść artykułu
  15. protected $tekst_artykulu;
  16. //zawiera datę utworzenia artykułu !!Unixowy znacznik czasu
  17. protected $utworzony;
  18. //zawiera datę ostatniej modyfikacji artykułu !!Unixowy znacznik czasu
  19. protected $zmodyfikowany;
  20. //zawiera datę ostatniej publikacji artykułu !!Unixowy znacznik czasu
  21. protected $opublikowany;
  22.  
  23.  
  24. protected $fieldsRequired = array('autor', 'kategoria', 'tytul', 'naglowek', 'utworzony' );
  25.  
  26. protected $dbhandle;
  27.  
  28.  
  29.  
  30. public function __construct($id=NULL)
  31. {
  32. $this->dbhandle = Database::GetInstance();
  33.  
  34. if($id)
  35. {
  36. $this->id_art = $id;
  37.  
  38. $sql = "SELECT *
  39. FROM j_artykuly
  40. WHERE id = $id";
  41.  
  42. $art = $this->dbhandle->select($sql);
  43.  
  44. if(!$art)
  45. throw new Exception('Wybrany artykuł nie istnieje');
  46.  
  47. $this->id = $id;
  48. unset($art[0]['id']);
  49. $this->setAll($art[0]);
  50. }
  51. }
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  /**
  58. * Metoda zwraca wartość jednego wybranego pola klasy
  59. *
  60. * @param name - nazwa pola w klasie, której wartość chcemy uzyskać
  61. **/
  62.  
  63. public function get($name)
  64. {
  65. if(property_exists(get_Class($this), $name))
  66. return $this->$name;
  67. else
  68. throw new Exception('Klasa '.get_class($this).' nie posiada pola '.$name);
  69. }
  70.  
  71. /**
  72. *
  73. * Metoda zwraca wartości wszystkich pól klasy
  74. *
  75. * @return tablica z danymi wszystkich pól;
  76. *
  77. **/
  78.  
  79. public function getAll()
  80. {
  81.  
  82. $arData = array(
  83. 'id' => $this->id,
  84. 'autor' => $this->autor,
  85. 'kategoria' => $this->kategoria,
  86. 'tytul' => $this->tytul,
  87. 'naglowek' => $this->naglowek,
  88. 'tekst_artykulu' => $this->tekst_artykulu,
  89. 'utworzony' => $this->utworzony,
  90. 'zmodyfikowany' => $this->zmodyfikowany,
  91. 'opublikowany' => $this->opublikowany,
  92. );
  93.  
  94. return $arData;
  95. }
  96.  
  97.  
  98. public function set($key, $value)
  99. {
  100. if($key == 'id')
  101. throw new Exception("Wartość pola 'id' może być nadana tylko automatycznie");
  102.  
  103. if(property_exists(get_Class($this), $key))
  104. {
  105. $this->$key = $value;
  106. }
  107. else
  108. throw new Exception('Klasa '.get_class($this).' nie posiada pola '.$key);
  109. }
  110.  
  111.  
  112. /**
  113. *
  114. * Metoda służy do ustawienia wartości pól w klasie
  115. *
  116. *@Param arData- tablica przechowująca nazwy pól i odpowiadające im wartości
  117. *
  118. **/
  119.  
  120. public function setAll(array $arData)
  121. {
  122. foreach($arData as $key => $value)
  123. {
  124. if($key == 'id')
  125. throw new Exception("Wartość pola 'id' może być nadana tylko automatycznie");
  126.  
  127. if(property_exists(get_Class($this), $key))
  128. {
  129. $this->$key = $value;
  130. }
  131. else
  132. throw new Exception('Klasa '.get_class($this).' nie posiada pola '.$key);
  133. }
  134. }
  135.  
  136.  
  137.  
  138. /**
  139. *
  140. * Metoda zapisująca lub tworząca artykuł w bazie danych
  141. *
  142. **/
  143.  
  144. public function saveArt()
  145. {
  146. if(empty($this->id))
  147. {
  148. $this->validateFields();
  149.  
  150. if($this->dbhandle->insert('j_artykuly', $this->getAll()) > 0);
  151. return true;
  152. }
  153. else
  154. {
  155. $this->validateFields();
  156.  
  157. $arConditions['id']=$this->id;
  158. if($this->dbhandle->update('j_artykuly', $this->getAll(), $arConditions) > 0);
  159. return true;
  160. }
  161. }
  162.  
  163.  
  164. /**
  165. *
  166. * Metoda usuwająca artykuł z bazy danych
  167. *
  168. **/
  169.  
  170. public function delArt()
  171. {
  172. if(!empty($this->id))
  173. {
  174. $this->validateFields();
  175.  
  176. $arWhere = array("id = ".$this->id);
  177. if($this->dbhandle->delete('j_artykuly', $arWhere) > 0)
  178. return true;
  179. }
  180.  
  181. throw new Exception('Nie można usunąć bierzącego artykułu, ponieważ nie został jeszcze zapisany w bazie danych.');
  182. }
  183.  
  184.  
  185. /**
  186. *
  187. * Metoda sprawdzająca czy pola, które nie mogą być puste w bazie danych, są wypełnione danymi
  188. *
  189. **/
  190.  
  191.  
  192. public function ValidateFields()
  193. {
  194. $arEmpty = array();
  195. foreach ($this->fieldsRequired as $field)
  196. {
  197. $value = $this->get($field);
  198. if (empty($value))
  199. $arEmpty[] = $field;
  200. }
  201.  
  202. if(count($arEmpty) > 0)
  203. {
  204. $empty = implode(', ', $arEmpty);
  205. throw new Exception('Wymagane pola '.$empty.' są puste.');
  206. }
  207.  
  208. return true;
  209. }
  210.  
  211.  
  212. ?>
  213.  
  214.  


Dodałem pole dbhandle w którym przechowywany będzie obiekt bazy danych. Kolejne dodane pole to $fieldsRequired w którym przechowywana jest tablica z polami wymaganymi do uzupełnienia. Zmodyfikowałem tez funkcję, która ma sprawdzać czy pola te są wypełnione. Na koniec połączyłem metody createArt i UpdateArt w jedną metodę SaveArt i usunełem pole new, a zamiast niego dałem sprawdzanie po id, według wczęsniejszej porady. Jak teraz według was wyglada moja klasa?

Go to the top of the page
+Quote Post
Speedy
post 26.08.2009, 00:15:35
Post #8





Grupa: Zarejestrowani
Postów: 651
Pomógł: 28
Dołączył: 4.12.2004

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


Bieżący piszemy przez ż z kropką.
Jak komentujesz metody i zmienne, to rób to konsekwentnie i komentuj wszystkie. Zachowaj jakiś standard komentowania - np. phpDocumentator.


--------------------
Sygnatura niezgodna z regulaminem.
Go to the top of the page
+Quote Post
Moli
post 26.08.2009, 07:48:00
Post #9





Grupa: Zarejestrowani
Postów: 662
Pomógł: 45
Dołączył: 26.03.2007
Skąd: Warszawa

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


Poczytaj o metodach magicznych.
Go to the top of the page
+Quote Post
czarek1986
post 26.08.2009, 09:15:09
Post #10





Grupa: Zarejestrowani
Postów: 72
Pomógł: 0
Dołączył: 15.09.2008

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


Cytat(Speedy @ 26.08.2009, 01:15:35 ) *
Bieżący piszemy przez ż z kropką.

Jak komentujesz metody i zmienne, to rób to konsekwentnie i komentuj wszystkie. Zachowaj jakiś standard komentowania - np. phpDocumentator.


Komentarze będą oczywiście przy każdej metodzie, na razie ich nie dodawałem bo nie wiem czy zaraz nie bedzie trzeba i tak tego usuwac smile.gif


Go to the top of the page
+Quote Post
ucho
post 26.08.2009, 09:58:50
Post #11





Grupa: Zarejestrowani
Postów: 300
Pomógł: 32
Dołączył: 31.07.2006

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


Cytat(czarek1986 @ 26.08.2009, 10:15:09 ) *
Komentarze będą

Nie ma co się oszukiwać - jak nie napiszesz od razu to w 95% przypadków te komentarze już nigdy nie powstaną tongue.gif
Go to the top of the page
+Quote Post

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

 



RSS Wersja Lo-Fi Aktualny czas: 24.04.2024 - 14:14