Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]pomoc przy dobrych praktykach i SOLID i laravel
Forum PHP.pl > Forum > Przedszkole
bialko0019
Hej. Jakiś czas temu zrozumiałem, że oprócz wiedzy i praktycznie wszelakich z tym związanych możliwościach, to nie tylko to, co programista znać powinien. Są też zasady, (jak standard w3c) których dobrze jest przestrzegać - i tak oto trafiłem na zasady SOLID - aż wstyd się przyznać, że wcześniej ich nie znałem.

Podpowiedzcie mi, na moich chociażby przykładach, jak powinno najlepiej się podchodzić do tematu.

1. Jeśli mamy Single Responsibility. Rozumiem to tak, że każdy obiekt powinien być tak robity, by poszczególne jego składowe, można było wykorzystywać w różnych sytuacjach. By nie tworzyć funkcji typu GetAll(). Czyli jeśli mam np. klasę Faktury. To dobrze, jest ją rozbić na składowe, które są odpowiedzialne za różne rzeczy. Np.

  1. $invoice = new Invoice->SearchInvoice(array('cos' => 'fv/8.2016'))->GetInvoiceId();
  2. $invoice = new Invoice->InsertInvoice(array('cos'=> 'ddd'))->GetInvoiceUrl();


czy lepiej to jeszcze bardziej rozbijać, np.:

  1. $invoice = new Invoice->Search(array('type' => 'invoice', 'cos' => 'fv11'))->GetId();


W pierwszym przypadku mam funkcję dedykowaną do szukania faktury SearchInvoice(). W zależności na jakich stronach wyszukuję faktury to piszę zawsze SearchInvoice() i wiem, że ta metoda zwraca faktury. A w drugim przypadku, jest metoda Search() którą mogę wykorzystać do szukania Faktur, ale też do szukania postów, do szukania użytkowników i szukania czegoś jeszcze. W drugim przypadku powstaje duża funkcja, w której jest dużo switch`ów, ale wykorzystywam ją w każdej stronie i nie muszę się zastanawiać co ona robi, a w pierwszym przypadku znowu większa ilość funkcji. Co jest lepsze prawidłowe?

2. Open Closed.

Mamy sytuację, że pobieram fakturę. Czyli lepiej jest tworzyć funkcję np. GetInvoicesById(1) , GetInvoicesTrashed(true, array('11', '22')) i tworzy się w tedy duża ilość funkcji, czyli lepszym będzie funkcja jak wyżej, czyli zawsze jako parametr dawać array (lub object) i wtedy nie trzeba dawać defaultowych wartości np.

  1. function funkcja($zmienna = 1, $limit = 10, $offset = 0, $returnId = true) { }


czy lepiej zawsze się przyzwyczaić i dawać:

  1. function funkcja($params)
  2. {
  3. if(!empty($params['limit'])) { $params['limit'] = 10; }
  4. if(!empty($params['offset'])) { $params['offset'] = 0; }
  5. //itd..


3. Co to jest encja tak właściwie? Object czyli zbiór metod, funkcje czyli można powiedzieć metody, a encje? to jakaś wartość funkcji, np:

  1. class jakas {
  2. private encja1 = '11';
  3. private encjejakas = '22';
  4. //itd...
  5. }



4. To już pytanie o Laravela. Jak się powinno fachowo generować podstrony i wykonywać routing. Załóżmy narazie prosty przykład, gdzie jest:

  1. Route::get('/{page}', function ($page, App\User $user, App\Cache $cache, App\Post $post) {
  2.  
  3. $PageDataType = new Post->SearchPost(array('slug' => $page'))->GetType();
  4. switch($PageDataType)
  5. {
  6. case 'post':
  7. $return = new Post->SearchPost(array('slug' => $page'))->GetAll();
  8. break;
  9. }
  10.  
  11.  
  12. return view('pages.'.$page, ['data' => $return]);
  13.  
  14. }
  15.  
  16. // i w templatce np. wyswietlamy dane itd.


Używam laravel 5.1 :-)


Z góry dziękuję za wszelkie wskazówki ;-)



Nikt nic?
markuz
Dużo masz pytań, postaram się odpowiedzieć na 1 żeby zachęcić resztę społeczności smile.gif

Single Responsibility
Cytat
Martin utożsamia odpowiedzialność klasy z powodem do jej modyfikacji. Możemy rozważyć moduł, który generuje i drukuje raport. Odpowiada on za dwa procesy, a tym samym mogą wystąpić dwa powody do jego modyfikacji. Po pierwsze, może zmienić się treść generowanego raportu, po drugie ? format, w jakim jest on drukowany. Zasada pojedynczej odpowiedzialności mówi, że oba te procesy powinny być niezależne i zaimplementowane w postaci dwóch oddzielnych klas lub modułów, które komunikują się ze sobą przy pomocy publicznych interfejsów


W Twoim przykładzie, żadna z odpowiedzi nie jest dobra.

  1. $invoice = new Invoice->SearchInvoice(array('cos' => 'fv/8.2016'))->GetInvoiceId();
  2. $invoice = new Invoice->InsertInvoice(array('cos'=> 'ddd'))->GetInvoiceUrl();


Czyli dla każdej tabeli/modelu musimy tworzyć osobne metody insert, serach itp. chociaż wyglądają tak samo - jedyna zmiana to będzie nazwa tabeli i ew. pól które chcemy zaznaczać, dodawać - odpada.

  1. $invoice = new Invoice->Search(array('type' => 'invoice', 'cos' => 'fv11'))->GetId();


Drugi sposób jest już bardziej w porządku, zakładajac, że metody search, insert itp. są w jakiejś nadrzędnej klasie np. "Model".

Cytat
W drugim przypadku powstaje duża funkcja, w której jest dużo switch`ów

Tutaj jest problem, nie powinno być switcha, tylko ta nadrzędna klasa powinna korzystać z właściwości tej podrzędnej np.

  1. <?php
  2.  
  3. class DataSource {
  4.  
  5. public function insert($tableName, $data) {
  6. echo "$tableName\n";
  7. foreach($data as $key => $value)
  8. echo "$key\t$value\n";
  9. }
  10.  
  11. }
  12.  
  13.  
  14. interface SimpleTableInterface {
  15.  
  16. public function getTableName();
  17.  
  18. }
  19.  
  20. class SimpleTable {
  21.  
  22. private $database;
  23. protected $tableName = null;
  24.  
  25. public function __construct(DataSource $database) {
  26. $this->database = $database;
  27. $this->tableName = $this->getTableName();
  28. }
  29.  
  30. public function insert($data) {
  31. return $this->database->insert($this->tableName, $data);
  32. }
  33.  
  34. }
  35.  
  36. class InvoiceTable extends SimpleTable implements SimpleTableInterface {
  37.  
  38. public function getTableName() {
  39. return 'invoces';
  40. }
  41.  
  42. }
  43.  
  44. $database = new DataSource();
  45. $invoces = new InvoiceTable($database);
  46. $invoces->insert([
  47. 'number' => 'FA-TEST-123'
  48. ]);
  49.  
  50. ?>


Metoda getTableName w klasie InvoiceTable komunikuje się z klasą SimpleTable za pomocą interfejsu SimpleTableInterface, po to aby klasa SimpleTable wiedziała na jakiej tabeli wykonywać określone zadania.

I teraz jeżeli np.
- zmienimy rodzaj bazy danych edytujemy tylko klasę DataSource nie ruszając innych rzeczy.
- chcemy pobierać faktury po numerze zamiast po ID to edytujemy klasę InvoiceTable dodawająć metode np. getByNumber.
- jakaś tam kolejna tabela np. Users przed insert musi hashować hasło - możemy to dodać tylko w tej klasie bez żadnego switch`a.

Nie jest to może idealny przykład i jestem pewny, że powyższy kod dało by się rozpisać o wiele lepiej - myślę jednak, że do zrozumienia "Single Responsibility" Ci wystarczy.
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.