Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Połączenie interfejsu z magic __call()
Forum PHP.pl > Forum > PHP > Object-oriented programming
shinuexx
Witam
Zastanawiałem się podczas tworzenia projektu jak rozwiązać problem połączenia metod wywoływanych poprzez __call() z metodami wymaganymi przez interfejs. Otóż zdefiniowałem sobie taki interfejs (chcę ujednolicić swoją kolekcję klas z kategorii działań arytmetycznych;P):
  1. interface MathExp{
  2. public function add(self $b);
  3. public function sub(self $b);
  4. public function mul(self $b);
  5. public function div(self $b);
  6. public function __toString();
  7. public function inv();
  8. public function _fileFormat();
  9. private function _extension_exists();
  10. public function fromString();
  11. public function sin();
  12. public function cos();
  13. public function tan();
  14. public function acos();
  15. public function asin();
  16. public function atan();
  17. public function cosh();
  18. public function sinh();
  19. public function tanh();
  20. public function exp();
  21. public function log();
  22. public function log10();
  23. public function mod(self $b);
  24. public function pow(self $b);
  25. public function sqrt();
  26. public function ceil();
  27. public function abs();
  28. public function floor();
  29. public function found();
  30. public function factorial();
  31. public function setScale($scale);
  32. public function getScale($scale);
  33. }

Zakładam też że wszelkie działania (np. dodawanie) mogą być wykonywane tylko z obiektem należącym właśnie do tego interfejsu. Jak dobrze myślę gdy klasa będzie to implementowała, to będzie musiała zawierać definicję tych metod co prawdopodobnie(jeśli mam rację;P) nie pozwoli na przechwycenie ich przez __call(). Dodatkowo zależy mi na łatwym rozszerzaniu całości bez modyfikacji istniejącego kodu.
Aby zobrazować mój problem wezmę np. metodę add() (dodawanie do siebie dwóch obiektów). Zamierzałem ją zaimplementować w ten sposób:
  1. public function add($b){
  2. if(!is_a($b,"MathExp"))
  3. throw new MathExpException(MathExpException::E_INVALID_INTERFACE_STR, MathExpException::E_INVALID_INTERFACE);
  4. $specific = "_add_".get_class($b);
  5. return $this->$specific($b);
  6. }

Jak wiadomo muszę odpowiednio sprecyzować to działanie dla dwóch różnych klas (inaczej doda rzeczywistą do rzeczywistej, zespoloną do zespolonej, rzeczywistą do zespolonej itd.) W związku z tym zamierzałem zrobić do tego w każdej klasie definicję dodawania (prywatną) dla różnych typów argumentu (np. _add_Numbers(), _add_Complex(), _add_Matrix() itp). Powoduje to, że metoda add() jak powyżej. Ale wtedy pojawia się problem powielania kodu, bo dla metody div() postąpię tak samo. Ale nie bez powodu utworzono metodę magiczną __call(), żeby powielać kawałki kodu.
W związku z tym zastanawiam się, czy nie lepiej by było zdefiniować w interfejsie, nie niewiele znaczącej metody add() a zamiast za to kilka metod _add_{class_name}() które będą odpowiadały za operację pomiędzy różnymi typami klas, a metodę add() przechytywać magicznie i wywoływać właśnie metodę dedykowaną dla argumentów?



Dałby radę ktoś podpowiedzieć, ocenić pomysłquestionmark.gif
michaJlS
Abstrahując od sensowności całości, możesz sobie trochę uprościć bez użycia __call

  1. private function _calc($b,$func){
  2. if(!is_a($b,"MathExp"))
  3. throw new MathExpException(MathExpException::E_INVALID_INTERFACE_STR, MathExpException::E_INVALID_INTERFACE);
  4. $specific = "_{$func}_".get_class($b);
  5. // tu możesz dodać sprawdzanie istnienia metody
  6. return $this->$specific($b);
  7. }
  8.  
  9. public function add($b){
  10. return $this->_calc($b,'add');
  11. }
  12.  


shinuexx
tzn co nie ma sensu bo nie za bardzo załapałem?
Crozin
Cytat
tzn co nie ma sensu bo nie za bardzo załapałem?
1. Grupowanie tych funkcji.
2. Pomysł użcia __call() - dowalanie magiczności.
ano
Cytat(shinuexx @ 25.03.2012, 23:16:48 ) *
  1. public function add($b){
  2. if(!is_a($b,"MathExp"))
  3. throw new MathExpException(MathExpException::E_INVALID_INTERFACE_STR, MathExpException::E_INVALID_INTERFACE);
  4. $specific = "_add_".get_class($b);
  5. return $this->$specific($b);
  6. }


a czemu nie po prostu:
  1. public function add(MathExp $b){ ... }


if nie będzie już potrzebny.
shinuexx
Czyli wszyscy mimo wszystko polecacie utrzymanie metody add()questionmark.gif Bo nie wiem czy zrozumieliście mój problem.
Metody tj: add, sub, mul, div, pow wywoływane jako publiczne będą miały za zadanie tylko i wyłącznie wybrać metodę prywatną, dedykowaną dla argumentów. Oznacza to, że dla tych funkcji kod będzie podobny. michalJS przedstawił mi bardzo sensowny sposób który trochę skraca kopiowany kod.

ano rzeczywiście tutaj mogę troszkę krócej:)
Crozin
Takie skracanie na siłę z reguły psuje kod, nie dając absolutnie nic w zamian.
shinuexx
Oki. Więc w tym temacie dowiedziałem się tego co chciałem:)
Można zamknąć temat.
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.