Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: trait vs interface
Forum PHP.pl > Forum > PHP
kayman
może chcę za dużo pisząc takie?


  1.  
  2. trait Tr {
  3.  
  4. public function getC() {
  5. echo 'asd';
  6. }
  7.  
  8. }
  9. }
  10.  
  11.  
  12. interface In {
  13.  
  14. public function getC();
  15.  
  16. }
  17.  
  18.  
  19. class B extends A implements In {
  20.  
  21. public function getC() {
  22. echo 'asd';
  23. }
  24.  
  25. }
  26.  
  27.  
  28. // a to wywala błąd
  29.  
  30.  
  31. class B extends A implements In {
  32.  
  33. use Tr;
  34.  
  35.  
  36. }
  37.  
  38.  


czyżby interface nie rozpoznaje metod wstrzykniętych przez trait?
Crozin
Cytat
a to wywala błąd
Nie uważasz, że informacja jaki błąd mogłaby być pomocna? I co to jest klasa A?
kayman
jak jest

  1.  
  2. class B extends A implements In {
  3.  
  4. use Tr;
  5.  
  6. }
  7.  


wywala błąd o braku metody

a jak zdejmę interface

  1.  
  2. class B extends A {
  3.  
  4. use Tr;
  5.  
  6. }
  7.  


kod działa
Pyton_000
  1. <?php
  2.  
  3. trait Tr {
  4. public function getC()
  5. {
  6. echo 'getC Trait'.PHP_EOL;
  7. }
  8. }
  9.  
  10. interface In {
  11. public function getC();
  12. }
  13.  
  14. class A {
  15.  
  16. }
  17.  
  18. class B extends A implements In
  19. {
  20. public function getC()
  21. {
  22. echo 'getC Class B'.PHP_EOL;
  23. }
  24.  
  25. }
  26.  
  27. class C extends A implements In
  28. {
  29. use Tr;
  30. }
  31.  
  32. $b = new B();
  33. $c = new C();
  34.  
  35. $b->getC();
  36. $c->getC();
Crozin
  1. <?php
  2.  
  3. interface In {
  4. function getC();
  5. }
  6.  
  7. trait Tr {
  8. public function getC() {
  9. return 'Tr.getC()';
  10. }
  11. }
  12.  
  13. class A {
  14.  
  15. }
  16.  
  17. class B1 extends A implements In {
  18. public function getC() {
  19. return 'B1.getC()';
  20. }
  21. }
  22.  
  23. class B2 extends A implements In {
  24. use Tr;
  25. }
  26.  
  27. class B3 extends A {
  28. use Tr;
  29. }
  30.  
  31. $b1 = new B1();
  32. $b2 = new B2();
  33. $b3 = new B3();
  34.  
  35. var_dump($b1->getC());
  36. var_dump($b2->getC());
  37. var_dump($b3->getC());
  38. var_dump($b1 instanceof In);
  39. var_dump($b2 instanceof In);
  40. var_dump($b3 instanceof In);
Kod
string(9) "B1.getC()"
string(9) "Tr.getC()"
string(9) "Tr.getC()"
bool(true)
bool(true)
bool(false)
Jak widać wszystko w porządku.

EDIT: Pyton_000 mnie trochę wyprzedził.
kayman
a teraz już zgłupiałem, co ma metoda z parenta wspólnego z interface?

Kod
Fatal error: Declaration of Framework\Models\Master\MasterModel::setData() must be compatible with Framework\Models\Master\ModelInerface::setData($id) in C:\xampp\htdocs\lpcms\Framework\Models\Master\TableUsers.php on line 18



  1.  
  2. interface ModelInerface {
  3.  
  4. public function __construct();
  5.  
  6. public function setData($id);
  7.  
  8. public function __set($key, $value);
  9.  
  10. public function __get($key);
  11.  
  12. public function getAll($order = null);
  13.  
  14. public function save();
  15.  
  16. public function getData($id = null);
  17.  
  18. public function delete($id);
  19.  
  20. }
  21.  
  22. trait ModelTraits {
  23.  
  24.  
  25. public function setData($id) {
  26. parent::setData($this->table, $this->columns, $id);
  27. }
  28.  
  29. public function __set($key, $value) {
  30. $this->set($this->table, $key, $value);
  31. }
  32.  
  33. public function __get($key) {
  34. return $this->get($this->table, $key);
  35. }
  36.  
  37. public function getAll($order = null) {
  38. return parent::getAll($this->table, $this->columns, $order);
  39. }
  40.  
  41. public function save() {
  42. parent::save($this->table);
  43. }
  44.  
  45. public function getData($id = null) {
  46. if ($id)
  47. $this->setData($id);
  48. return parent::getData($this->table);
  49. }
  50.  
  51. public function delete($id) {
  52. parent::delete($this->table, $id);
  53. }
  54.  
  55. }
  56.  
  57.  
  58. class TableUsers extends MasterModel implements ModelInerface {
  59.  
  60. private $table = 'users';
  61. private $columns = array('id', 'mail', 'pass', 'level', 'firstname', 'lastname', 'lang');
  62.  
  63. public function __construct() {
  64. parent::__construct($this->table, $this->columns);
  65. }
  66.  
  67. use ModelTraits;
  68.  
  69. // cut
  70.  
  71. }
  72.  
  73. class MasterModel {
  74.  
  75. public $data;
  76.  
  77. public function __construct($table, $columns) {
  78. foreach ($columns as $value) {
  79. $this->data[$table][$value] = null;
  80. }
  81. }
  82.  
  83. public function setData($table, $columns, $id) {
  84. $query = new QueryBuider();
  85. $query->setColumns($columns);
  86. $query->setFrom($table);
  87. $query->addWhere('id', $id);
  88. $sql = \Framework\Libs\Sql::instance();
  89. $data = $sql->getSingleRow($query->getSelect());
  90. foreach ($columns as $value) {
  91. $this->data[$table][$value] = $data[$value];
  92. }
  93. }
  94.  
  95. // cut
  96.  
  97. }
  98.  
  99.  

Pyton_000
To że deklarujesz kontrakt (interfejs) z jednym parametrem a deklarujesz metodę z 3. To jest niezgodność deklaracji z interfejsem.
Crozin
Masz niekompatybilne sygnatury metod. Nie ma to żadnego związku z interfejsami czy traitsami.
  1. class A
  2. {
  3. public function abc($abc, $cde, MyClass $def)
  4. {
  5. // jakaś implementacja
  6. }
  7. }
  8.  
  9. class B extends A
  10. {
  11. public function abc($abc, $cde, def) // błąd, niekompatybilne sygnatury
  12. {
  13. // jakaś implementacja
  14. }
  15.  
  16. public function abc() // błąd, niekompatybilne sygnatury
  17. {
  18. // jakaś implementacja
  19. }
  20.  
  21. public function abc($abc, $cde, MyClass $def) // OK
  22. {
  23. // jakaś implementacja
  24. }
  25. }

kayman
czyli to jest żle i trzeba by np. inaczej nazwać metodę w parencie

  1.  
  2. public function setData($id) {
  3. parent::setData($this->table, $this->columns, $id);
  4. }
  5.  
  6. //zmienić np tak
  7.  
  8. public function setData($id) {
  9. $this->setMasterData($this->table, $this->columns, $id);
  10. }
  11.  
  12.  


a to dobrze

  1.  
  2. public function __get($key) {
  3. return $this->get($this->table, $key);
  4. }
  5.  
Crozin
1. Wykorzystanie magicznego __get() jest raczej złym pomysłem. Dlaczego nie zrobisz zwykłej metody get(), getTableProperty() czy jakkolwiek inaczej nazwanej?
2. Nie wiem co dokładnie chcesz osiągnąć, więc ciężko napisać co byłoby dobrym rozwiązaniem.
kayman
chciałem np takie coś

  1.  
  2. $id = getNpZSessji();
  3.  
  4. $user = new TableUser();
  5.  
  6. $user->setData($id);
  7.  
  8. echo 'Witaj ' . $user->firstname . '. Twoje id to '. $user->id;
  9.  
  10.  
  11. //lub
  12.  
  13. $user = new TableUser();
  14.  
  15. $user->setData($id);
  16.  
  17. $user->firstame = 'Tomek';
  18.  
  19. $user->save(); // jest id -> update;
  20.  
  21. //albo
  22.  
  23. $user = new TableUser();
  24.  
  25. $user->firstame = 'Tomek';
  26. //$user->lastname = costam etc
  27.  
  28. $user->save(); // brak id -> insert;
  29.  


i analogicznie do wszystkich tabel w bazie danych takie mapowanie

do tego np takie konstrukcje incydentalne do poszczególnych tabel

  1.  
  2. $log = new TableLogs();
  3. $log->addLog('zmiana wartości tu i tu');
  4.  
  5. // co jest równoznaczne z
  6.  
  7. $log = new TableLogs();
  8. $log->addtime = mktime();
  9. $log->user_id = $SESSION['user_id'];
  10. $log->content = 'zmiana wartości tu i tu';
  11. $log->save();
  12.  
  13.  


Pyton_000
setData możesz spokojnie wywalić i dać w konstruktor.

W tym przypadku nie potrzebujesz ogólnie interfejsu.

Robisz sobie klasę bazową Model która zastępuje Ci trait i interface (możesz zrobić abstract żeby jej nie instancjować) a poszczególne modele extends Model i wsio. Nie ma co kombinować smile.gif
kayman
Cytat(Pyton_000 @ 26.01.2015, 15:48:51 ) *
setData możesz spokojnie wywalić i dać w konstruktor.


imo nie -> bo setData jest dla rekordu który istnieje

ja widzę to tak

  1.  
  2. $page = new TablePages();
  3. if(isset($_POST['id']) {
  4. $page->setData($_POST['id']);
  5. }
  6. $page->url = $_POST['url'];
  7. $page->save(); // insert lub update
  8.  
Pyton_000
ihmo
  1. $page = new Page(12);
  2.  
  3. if(!$page)
  4. {
  5. // Insert
  6. $page->title = 'ala';
  7. $page->save();
  8. }
  9.  
  10. $page->title = 'Klocek';
  11. $page->save(); //Update
kayman
dzięki panowie, wiem mniej więcej jak to przebudować by było "do ręki" i nie powielać kodu
Crozin
1. Takie podejście, czyli tzw. ActiveRecord, jest raczej słabym rozwiązaniem. W Google znajdziesz więcej na ten temat.
2. Temat dotyczy na dobra sprawę ORM-a. Pomyśl nad wykorzystaniem Doctrine.
Pyton_000
Może też użyć lżejszego Eloquent z Laravela, ale nie proponowałem bo stwierdziłem że autor robi to dla sportu wink.gif
kayman
nie mam nic przeciwko ORM z prawdziwego zdarzenia jak Doctrine, Propel, chciałam sprawę uprościć na własne potrzeby a przy okazji czegoś się nauczyć

mam wrażenie, że deklaracja klasy odpowiadającej za obsługę jakiejś tabeli w bazie nie wyszła najgorzej a przy wykorzystaniu trait będzie w miarę szybka do napisania i w miarę czytelna
Pyton_000
W Twoim Przypadku Trait nie jest potrzebny Bo:
- i tak nigdzie go nie wykorzystasz więcej niż w tych Modelach
- Musisz dołączać Trait i Interface

Lepiej już:
- Zostawić interface
- Zrobić klasę DbModel implementującą interfejs
- Dziedziczyć po DbModel

A jeszcze lepiej to dziedziczyć po Fabryce Model dzięki czemu będziesz mógł w bardzo szybki sposób zmienić implementację z BD na File np.
kayman
Pyton masz racje tylko w ten sposób zaraz napiszę kombajn a nie uproszczę całość a w takim wypadku już chyba lepiej skorzystać z gotowego rozwiązania bo szkoda czasu

btw. inteface można by chyba wywalić stosując trait bo metody i tak są w trait te co potrzeba
Pyton_000
Jeżeli chcesz się czegoś nauczyć to możesz rozwijać, a jak chcesz tylko coś co działa to możesz to zostawić tak jak jest lub brać coś gotowego.
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.