Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: prośba o krytykę kodu
Forum PHP.pl > Inne > Oceny
dżozef
jako, że nie jestem "PRO" w PHP chciałbym swoje ewentualne błędy korygować na bieżąco, czy mógłby ktoś rzucić okiem na mój kod i go skrytykować conieco?
  1. <?php
  2. class Domains {
  3. private $_total = 0; // store total number of domains
  4. private $_good = 0; // store number of domains in good standing
  5. private $_expiring = 0; // store number of expiring domains
  6. private $_expired = 0; // store number of expired domains
  7. private $_domains = array();
  8.  
  9. public function __construct() {
  10. $this->_domains=$this->fetchAll();
  11. }
  12. // returns a number of domains
  13. public function numTotal() {
  14. return $this->_total;
  15. }
  16. // returns number of good domains
  17. public function numGood() {
  18. return $this->_good;
  19. }
  20. // returns number of expiring domains
  21. public function numExpiring() {
  22. return $this->_expiring;
  23. }
  24. // returns number of expired domains
  25. public function numExpired() {
  26. return $this->_expired;
  27. }
  28. // validates domain data
  29. public function validate($domain) {
  30. $_result = true;
  31. // perform check here
  32. return $_result;
  33. }
  34. // get a domain details for domain with given id
  35. public function get($id) {
  36. // basically we are going through the whole list and if we find a match we return the content
  37. foreach($this->_domains as $domain) {
  38. if ($domain['dom_id']==$id)
  39. {
  40. $_result=$domain;
  41. return $_result;
  42. }
  43. }
  44. // in case we won't find the match let's indicate it
  45. $_result=-1;
  46. return $_result;
  47. }
  48. // delete domain
  49. public function delete($id) {
  50. $_result = false;
  51. try {
  52. $conn=DB::getConnection();
  53. $query=$conn->prepare("DELETE FROM `domains`
  54. WHERE dom_id=:dom_id");
  55. $query->execute(array('dom_id' => $id));
  56. $_result = true;
  57. }
  58. catch (PDOException $e)
  59. {
  60. trigger_error('Domains: error deleting domain');
  61. $_result = false;
  62. }
  63. // let's reload just in case to reflect changes
  64. $this->_domains = $this->fetchAll();
  65. return $_result;
  66. }
  67. // update database with $domain, all required info should be there STUB
  68. public function update($domain) {
  69. $_result = false;
  70. try {
  71. $conn=DB::getConnection();
  72. $query=$conn->prepare("UPDATE `domains`
  73. SET dom_name=:dom_name, dom_reg_id=:dom_reg_id, dom_reg_date=:dom_reg_date,
  74. dom_exp_date=:dom_exp_date, dom_comment=:dom_comment, dom_status=0
  75. WHERE dom_id=:dom_id");
  76. $query->execute(array('dom_id' => $domain['dom_id'],
  77. 'dom_name' => $domain['dom_name'],
  78. 'dom_reg_id' => $domain['dom_reg_id'],
  79. 'dom_reg_date' => $domain['dom_reg_date'],
  80. 'dom_exp_date' => $domain['dom_exp_date'],
  81. 'dom_comment' => $domain['dom_comment']
  82. ));
  83. $_result = true;
  84. }
  85. catch (PDOException $e)
  86. {
  87. trigger_error('Domains: error updating domain');
  88. $_result = false;
  89. }
  90. // let's reload just in case to reflect changes
  91. $this->_domains = $this->fetchAll();
  92. return $_result;
  93. }
  94. // insert a domain into database STUB
  95. public function insert($domain) {
  96. $_result = false;
  97. // check if this is a valid domain
  98. if ($this->validate($domain)) {
  99. // perform insert here
  100. try {
  101. $conn=DB::getConnection();
  102. $query=$conn->prepare("INSERT INTO `domains` (dom_name, dom_reg_id, dom_reg_date, dom_exp_date, dom_comment)
  103. VALUES (:dom_name, :dom_reg_id, :dom_reg_date,
  104. :dom_exp_date, :dom_comment)");
  105. $query->execute(array( 'dom_name' => $domain['dom_name'],
  106. 'dom_reg_id' => (int)$domain['dom_reg_id'],
  107. 'dom_reg_date' => $domain['dom_reg_date'],
  108. 'dom_exp_date' => $domain['dom_exp_date'],
  109. 'dom_comment' => $domain['dom_comment'],
  110. ));
  111. $_result = true;
  112. }
  113. catch (PDOException $e)
  114. {
  115. trigger_error('Domains: error inserting domain'+$e);
  116. $_result = false;
  117. }
  118. } else
  119. {
  120. trigger_error('Domains: trying to insert invalid domain data.');
  121. }
  122. // let's reload just in case to reflect changes
  123. $this->_domains = $this->fetchAll();
  124. return $_result;
  125. }
  126. // fetch all domains from database
  127. public function fetch() {
  128. try {
  129. $this->_total=0;
  130. $this->_expired=0;
  131. $this->_expiring=0;
  132. $this->_good=0;
  133. // open connection and create query
  134. $conn=DB::getConnection();
  135. $today = date("Y-m-d");
  136. // get all domains and calculate how many days left based on current date and exp_date
  137. $query=$conn->prepare("SELECT dom_id, dom_name, dom_reg_id, dom_reg_date, dom_exp_date,
  138. dom_comment, dom_status, TIMESTAMPDIFF(DAY, :today,
  139. domains.dom_exp_date) as dom_days_left
  140. FROM `domains`, `registrars`
  141. WHERE dom_reg_id=reg_id
  142. ORDER BY dom_days_left");
  143. $query->execute(array('today' => $today));
  144. $result = $query->fetchAll();
  145. $data = '';
  146. foreach ($result as $row) {
  147. $this->_total++;
  148. if ($row['dom_days_left']>30) {
  149. $row['Status']=DOMAIN_OK;
  150. $this->_good++;
  151. }
  152. elseif ($row['dom_days_left']>1) {
  153. $row['Status']=DOMAIN_EXPIRING;
  154. $this->_expiring++;
  155. }
  156. else {
  157. $row['Status']=DOMAIN_EXPIRED;
  158. $this->_expired++;
  159. }
  160. $data[]=$row;
  161. }
  162. }
  163. catch (PDOException $e)
  164. {
  165. // show error message upon PDO error
  166. trigger_error('Domains: error fetching domains table: '.$e);
  167. return false;
  168. }
  169. $this->_domains=$data;
  170. return $data;
  171. }
  172. // fetch an array of good domains
  173. public function fetchAll() {
  174. return $this->fetch();
  175. }
  176. // fetch an array of good domains
  177. public function fetchGood() {
  178. // browse all domains
  179. foreach ($this->_domains as $row) {
  180. if ($row['dom_days_left']>30)
  181. // add domains with more than 30 days left to result
  182. $data[]=$row;
  183. }
  184. return $data;
  185. }
  186. // fetch an array of good domains
  187. public function fetchExpiring() {
  188. // browse all domains
  189. foreach ($this->_domains as $row) {
  190. // add domains between 1 and 30 days to result
  191. if ($row['dom_days_left']>1 && $row['dom_days_left']<=30)
  192. $data[]=$row;
  193. }
  194. return $data;
  195. }
  196. // fetch an array of good domains
  197. public function fetchExpired() {
  198. // browse all domains
  199. foreach ($this->_domains as $row) {
  200. // add ones below one day to the result
  201. if ($row['dom_days_left']<=1)
  202. $data[]=$row;
  203. }
  204. return $data;
  205. }
  206. }

ewentualnie na gist: https://gist.github.com/mprz/6cce0e6dd51e4796209c
Spawnm
DOMAIN_OK, DOMAIN_EXPIRING, gdzie ty to deklarujesz?
Trigger_error <- co to za cudo z średniowiecza?
Czemu każda metoda wywołuje DB::getConnection(); ? Daj to w konstruktorze.
Private $_expired i już wiem że nici z wygodnego dziedziczenia.
dżozef
deklaracje są w config.inc.php, ale już załapałem że lepiej będzie trzymać w klasie
trigger_error jest tam w tylko w fazie 'development', później zmienię na logowanie błędów do pliku
co do prywatnych zmiennych - przecież do wszystkich są gettery, jeśli nie planuję rozszerzalności klasy nie mógłbym ich zostawić jako private? znam różnicę między private i protected

edit: nowa wersja, zmienione private->protected, dodane stałe, jedna zmienna dla połączenia PDO
https://gist.github.com/mprz/6cce0e6dd51e4796209c
peter13135
Czemu nazwy składowych zaczynają się od znaku _ ? Czy to nie jest naleciałość po php4 gdzie nie było jeszcze private ? Czy nadal jest to potrzebne ?Nie wiem czy to błąd, czy nie. Po prostu pytam.

Masz sporo komentarzy. Według Wujka Boba, komentarz to "zło konieczne" gdy kod nie opisuje sam siebie. Czy więc zamiast metody o nazwie delete, nie lepiej nazwać ja deleteDomian ? smile.gif
Podobnie metoda numExpiring() z komentarzem "returns number of expiring domains", mogła by się obejść bez komentarza, jeśli nazwalibyśmy ją getNumExpiringDomains()
dżozef
dzięki za rady!

- podkreślenie służy mi temu, że od razu wiem, która zmienna jest public a która private/protected. podejrzałem to gdzieś i zdaje się mi służyć
- naczytałem się troche o konwencji nazw dla PHP (i OOD wogóle) i pamiętam, że duży nacisk położony był na nie dołączanie do nazw metod nazwy klasy. czyli:
  1. $domain = new Domain();
  2. $zmienna=$domain->delete();

a nie
  1. $domain = new Domain();
  2. $zmienna=$domain->deleteDomain();

gdzie druga wersja niepotrzebnie powiela Domain
wydaje mi się to rozsądnie pomyślane, dlatego robię to w ten sposób

peter13135
Fakt, z tym się zgodzę. Nawet nie spojrzałem na nazwę klasy. W takim razie, komentarz "// delete domain" dla metody delete w klasie domain moim zdaniem jest zbyteczny, bo nie mówi niczego więcej ponad to, co wnioskujemy po nazwie klasy i metody. Być może czepiam się pierdół. Po prostu kod jest (moim zdaniem) na tyle dobry, że czepiam się tego co się da wink.gif

Według Wujka Boba współczesne IDE są na tyle rozbudowane, że takie podkreślenia lub inne prefixy są zbyteczne.
dżozef
Cytat(peter13135 @ 12.06.2013, 23:10:23 ) *
Po prostu kod jest (moim zdaniem) na tyle dobry, że czepiam się tego co się da wink.gif

wow, dzięki smile.gif to moja pierwsza aplikacja

Cytat(peter13135 @ 12.06.2013, 23:10:23 ) *
Według Wujka Boba współczesne IDE są na tyle rozbudowane, że takie podkreślenia lub inne prefixy są zbyteczne.

bardziej chodzi mi o to, że to JA widzę, która zmienna jest/nie jest publiczna
Spawnm
  1. Czemu nazwy składowych zaczynają się od znaku _ ? Czy to nie jest naleciałość po php4 gdzie nie było jeszcze private ? Czy nadal jest to potrzebne ?Nie wiem czy to błąd, czy nie. Po prostu pytam.

Tyle razy były już o tym dyskusje. Zaczynanie metod private/protected od _ ma sens i jest nadal bardzo przydatne.
dżozef
uaktualnienie: kilka funkcji nie sprawdzało czy zwracana wartość została zainicjowana. dodałem parę warunków w kodzie, i zwracane jest -1 jeśli $_result jest unset()
Spawnm
czemu -1? o.O Zwracaj false.

Na szybko klepnąłeś, nie chciało ci się ochłonąć i pomyśleć.
Zamiast tego:
  1. // get a domain details for domain with given id
  2. public function get($id) {
  3. // basically we are going through the whole list and if we find a match we return the content
  4. foreach($this->_domains as $domain) {
  5. if ($domain['dom_id']==$id)
  6. {
  7. $_result=$domain;
  8. return $_result;
  9. }
  10. }
  11. // in case we won't find the match let's indicate it
  12. $_result=-1;
  13. return $_result;
  14. }

Daj np. to:
  1. // get a domain details for domain with given id
  2. public function get($id) {
  3. // basically we are going through the whole list and if we find a match we return the content
  4. foreach($this->_domains as $domain) {
  5. if ($domain['dom_id']==$id)
  6. {
  7. return $domain;
  8. }
  9. }
  10. // in case we won't find the match let's indicate it
  11. return false;
  12. }

Ewentualnie jeśli zależy ci na zachowaniu $return:
  1. // get a domain details for domain with given id
  2. public function get($id) {
  3. // basically we are going through the whole list and if we find a match we return the content
  4. $result = false;
  5. foreach($this->_domains as $domain) {
  6. if ($domain['dom_id']==$id)
  7. {
  8. $result=$domain;
  9. }
  10. }
  11. return $result;
  12. }


Jeśli robisz lokalne zmienne takie jak $result, nie ma sensu dawać _ czyli $_result. Znak _ dajesz dla private/protected.
emp
Cytat(dżozef @ 12.06.2013, 23:04:09 ) *
- podkreślenie służy mi temu, że od razu wiem, która zmienna jest public a która private/protected. podejrzałem to gdzieś i zdaje się mi służyć


To źle ci służy. Wszystkie dane( pola ) dobrze zaprojektowanej klasy powinny być prywatne ( enkapsulacja danych ), więć nie ma żadnego powodu by dodawać do nich podkreślink skoro wszystkie są prywatne. Dane chornione czy publiczne to są bardzo specjalne przypadki. Dostęp do danych klasy powinien odbywać się tylko przez metody dostępowe i to one są najwyżej chronione. Interfejs jest publiczny.Podkreślnik przed zmiennymi prywatnymi to zboczenie programistów javy ponieważ tam można odwołać się do pola klasy beż this w jej obrębie i nie widać czy to zmienna lokalna czy klasy na pierwszy rzut oka. Pozatym zmiennych lokalnych nie powinno się używać tylko zapytania. Zastępujemy zmienną tymczasową zapytaniem.

Twoja klasa jest odpowiedzialna za 2 rzeczy czyli o jedną za dużo. Widze tu... póki jeszcze nie zarzuciłem bielunia to widze... obiekt dziedziny domain i utrwalanie go. 2 klasy bym tu minimum widział oczywiscie domain i np domain_table. Warstwa dziedziny i warstwa utrwalania. Domain bedzie delegować do domain_table. domain_table będzie polem klasy domain.

Na pewno musisz zastosować te przekształcenia tak na oko
* Rozdzielenie Zapytania i Modyfikacji
* Zastąpienie odwołania do zmiennej zapytaniem
* Ekstrakcje klasy ( z domain wyciagnij np domain_table )
* Ekstrakcje metody ( podzialkuj dlugie metody )
* Przeniesienie metody ( przenies do domain_table z domain )
Zastosować jakiś wzorzec do mapowania realcyjno-obiektowego
* Brama danych tabeli
* Brama danych wiersza
* Rekord aktywny
* Data mapper to by była w tym wypadku lekka przesada.

Dobrze że używasz instrukcji preparowanych i nazwanych symboli zastępczych ci którzy tak nie robią robią po prostu siare.

Każdy kto nie czytał tych ksiązek jak i welu innych klasyków, a programuje powinien się wstydzić i kajać.
Refaktoryzacja ulepszanie struktury istniejacego kodu
Architektura systemow zarzadzania przedsiebiorstwem wzorce projektowe
Wracam do szukania bielunia obok firmy może coś znajde. Pissss joł.
peter13135
Cytat
Podkreślnik przed zmiennymi prywatnymi to zboczenie programistów javy ponieważ tam można odwołać się do pola klasy beż this w jej obrębie i nie widać czy to zmienna lokalna czy klasy na pierwszy rzut oka.

Osobiście w javie nie spotkałem się z takimi zmiennymi. Metoda teoretycznie powinna być bardzo mała, a współczesne IDE tak kolorują składnie, by wiadomo było, czy zmienna jest składową klasy, czy lokalną w metodzie - dlatego nadal nie widzę powodu, by programiścy javy (i czemu akurat javy? w cpp też nie trzeba używać thisa) używali tego podkreślenia. Pewnie za mało kodu w javie widziałem albo oglądam tylko ten lepszy kod.
Natomiast podkreślenia w zmiennych prywatnych to bardzo częste zachowanie programistów PHP4 gdzie każda zmienna była publiczna (słowo kluczowe var), a dodanie podkreślenia na początku miało sygnalizować - tą zmienną traktuj jak prywatną, bo ona byłaby prywatna gdyby tylko php4 na to pozwoliło.

Cytat
i zwracane jest -1 jeśli $_result jest unset()

A czy tutaj nie lepiej skorzystać z wyjątków ? Wiem, że wyjątki w php to takie troche sztuczne są (choćby dlatego, że wyjątkami nie zostały objęte wbudowane funkcje), ale jak już mówimy o czystym kodzie, to wyjątki są po to, żeby ułatwić pisanie czystego kodu.

Cytat
Tyle razy były już o tym dyskusje. Zaczynanie metod private/protected od _ ma sens i jest nadal bardzo przydatne.

Wybacz, nie widziałem ani jednego wątku. W książce, którą czytałem używanie podkreślenia było krytykowane. Chętnie poznam inne opinie na ten temat, więc jakimś linkiem nie pogardzę wink.gif


  1. // fetch an array of good domains
  2. public function fetchExpiring();
  3. // fetch an array of good domains
  4. public function fetchExpired();


takie same komentarze, dla dwóch metod ? Chyba cośtu jest nie tak.

Według Wujka Boba, takie warunki:
Cytat
if ($row['dom_days_left']>1 && $row['dom_days_left']<=30)

powinny być wyexportowane do innej metody. Np
  1. if($this->domDaysLeftBetween1And30($row))

Albo
  1. if($this->isBetween1And30($row[dom_days_left]))


Nie wiem, który wariant lepszy, ale ten drugi zdaje się nie pasować do klasy o nazwie Domain wink.gif

wtedy komentarz:
Cytat
// add domains between 1 and 30 days to result

będzie niepotrzebny.

Wadą tego rozwiązania jest oczywiście mniejsza wydajność (pewnie bardzo nieznaczna, ale w javie stosowany jest silny inlining, tutaj raczej nie bardzo.), większe rozbicie kodu (więcej metod) za to kod jest czytelniejszy i potrzebuje mniej komentarzy, które to lubią tracić na aktualności.
Spawnm
Cytat
f($this->isBetween1And30($row[dom_days_left]))

Lol, jaka nazwa biggrin.gif
  1. if($this->isBetween($row[dom_days_left], 1, 31))


@down - nie dziś wink.gif
peter13135
Fakt, Twoja lepsza wink.gif Ale ideę chyba miałem w miarę dobrą.

Czy dasz mi jakieś "materiały" udowadniające słuszność zastosowania prefixu "_" w prywatnych składowych ?
dżozef
progi 1 i 30 teraz są arbitralne ale będą definiowalne przez użytkownika nieco później (roadmap), więc zawczasu się przygotowałem do tego
ale można pomyśleć nad
  1. isBetween($row[dom_days_left], $próg1, $próg2)
peter13135
Cytat
@down - nie dziś

Czyli pewnie ani jutro, ani po jutrze wink.gif
!*!
Cytat(peter13135 @ 13.06.2013, 22:43:34 ) *
Czy dasz mi jakieś "materiały" udowadniające słuszność zastosowania prefixu "_" w prywatnych składowych ?

http://forum.php.pl/index.php?s=&showt...t&p=1041806
wink.gif
Spawnm
!*! - Było kiedyś coś ciekawszego.
peter13135
OK. przeczytałem. Nie mam zamiaru się kłócić, bo widzę, że zdania są podzielone. Do mnie jednak trafiają te argumenty :
1. Dobry kod nie posiada zmiennych publicznych.
2. IDE koloruje zmienne tak, że bez problemu można odróżnić, cy jest to zmienna lokalna czy instancji obiektu.
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-2024 Invision Power Services, Inc.