Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Rozszerzenie klasy
Forum PHP.pl > Forum > PHP > Object-oriented programming
Fifi209
Witam!

Potrzebuję podzielić widok, na kilka klas. Dokładniej chcę mieć główny widok i klasy które rozszerzą jego możliwości.

Nie byłoby problemu, bo mógłbym nawet dziedziczyć tylko, że potrzebuję użyć np. 3-4 rozszerzeń naraz.

Przykłady rozszerzeń:
- Klasa obsługująca szablony (parsowanie etc.)
- Klasa parsująca bb-code
- Klasa tworząca formularze

Sam wymyśliłem coś takiego:

Klasa widok, ma metodę:
  1. public function _load($name) {
  2. if ($this->$name) {
  3. return $this->$name;
  4. }else{
  5. $temp = __CLASS__ .'_'. $name;
  6. if (file_exists('modules/'.$temp.'.php')) {
  7. include_once('modules/'.$temp.'.php');
  8. return $this->$name = new $temp;
  9. }else{
  10. return false;
  11. }
  12. }
  13. }


Problem polega na tym, że używanie tak wczytanego modułu jest niewygodne, bo muszę robić to np. tak:
  1. $view->template->metoda();


Od razu tutaj zaznaczę, że mam magiczną metodę __get() dlatego odwołuję się poprzez $view->template.

Co w tym niewygodnego? Muszę wszystko zwracać returnami, bo inaczej nic w widoku nie zapiszę.

Dokładniej:

  1.  
  2. $view = view::create(); // Zwraca obiekt, wzorzec singleton
  3. $view->_load('template');
  4.  
  5. // działania na template np.
  6. $view->template->_loadFile('tpl/index.tpl');
  7.  
  8. // Powiedzmy podmieniamy co mamy podmienić w szablonie
  9. $podmiana = array('title' => 'test', 'content' => 'testy');
  10.  
  11. foreach ($podmiana as $key => $value) {
  12. $view->template->add($key, $value);
  13. }
  14.  
  15. // zapis wyniku działania modułu template
  16. $view->save($view->template); // i to mi się nie podoba, dałem sobie


To co mi się nie podoba, działa akurat na zasadzie wywołania __toString, który uruchamia parser template.
Z template jest najmniejszy problem, gorzej z robieniem formów... Gdzie np. każdego inputa muszę zapisać do zmiennej i potem $view->save($zmiennaZinputem)

Jak za słabo objaśniłem to czekam na pytania. haha.gif
-=Peter=-
Nie wiem czy dobrze zrozumiałem Twój problem, ale jeśli w aplikacji istnieje "zapach" wielodziedziczenia to dekorator powinien dać radę ;] Ewentualnie możesz zrobić "złożony" widok (Composite), do którego dodajesz te widoki podrzędne o których mówisz, a widok główny deleguje zadania kolejno do każdego z widoków podrzędnych i składa wynik.
Fifi209
Cytat(-=Peter=- @ 10.08.2009, 12:19:43 ) *
Nie wiem czy dobrze zrozumiałem Twój problem, ale jeśli w aplikacji istnieje "zapach" wielodziedziczenia to dekorator powinien dać radę ;]

Tutaj nie ma dziedziczenia, napisałem że gdyby chodziło o jeden moduł rozszerzający naraz to bym dziedziczył, w przeciwnym wypadku (tym) nie mogę.

Cytat(-=Peter=- @ 10.08.2009, 12:19:43 ) *
Ewentualnie możesz zrobić "złożony" widok (Composite), do którego dodajesz te widoki podrzędne o których mówisz, a widok główny deleguje zadania kolejno do każdego z widoków podrzędnych i składa wynik.

Nie wiem czy dobrze zrozumiałem, ale właśnie do głównego widoku ładuję te moduły rozszerzające czy jak to nazwałeś widoki podrzędne.
erix
Nie wiem, czy u Ciebie nie byłby dobry wzorzec Adapter.

Cytat
Jak za słabo objaśniłem to czekam na pytania.

Trochę nie jarzę, jak chcesz w ogóle to wszystko osiągnąć - żeby samo wczytywało wstawki i automatycznie je wykonywało?
Fifi209
Cytat(erix @ 10.08.2009, 13:16:43 ) *
Trochę nie jarzę, jak chcesz w ogóle to wszystko osiągnąć - żeby samo wczytywało wstawki i automatycznie je wykonywało?


Chodzi mi o to, abym mógł w prosty sposób rozwiązać "komunikację" głównego widoku z modułami rozszerzającymi.

Przykładowo moduł do form, powiedzmy tworzenie inputa:

  1.  
  2. $params = array('type' => 'text', 'name' => 'test');
  3.  
  4. $input = $view->form->createInput($params);
  5.  
  6. // i muszę go zapisywać tak:
  7. $view->save($input);
  8.  


Chodzi mi o to, aby po wywołaniu $view->form->createInput była jakby "automatycznie" wywoływana $view->save(), abym nie musiał tworzyć kolejnej zmiennej w tym wypadku $input.

Bo robi się bałagan jak robię np. 3 inputy (login, hasło, submit)

Jednym słowem wszystko jest jakieś niewygodne.

Jak trzeba to pokażę moje testowe/przejściowe rozwiązanie, napisane na kolanie.
erix
Cytat
Chodzi mi o to, aby po wywołaniu $view->form->createInput była jakby "automatycznie" wywoływana $view->save(), abym nie musiał tworzyć kolejnej zmiennej w tym wypadku $input.

Hmm, to może zrób wg tego:

  1. // konstruktor wstawki
  2. $klasa = new klasa;
  3. $klasa->view = $this;

i potem wewnątrz tamtej klasy wywołujesz, co trzeba.
skowron-line
Nie jestem ekspertem w OOP i może napisze niezłą głupotę ale czy __call by ci nie pomogło questionmark.gif
__call
Fifi209
Chyba lepiej pokaże moje rozwiązanie na kolanie pisane:

Klasa view (główna) do niej "ładuję" moduły
  1. <?php
  2.  
  3. class view {
  4.  
  5. protected $content;
  6. private $modules;
  7.  
  8. private function __construct() {}
  9.  
  10. public function __toString() {
  11. if ($this->content) {
  12. return $this->content;
  13. }else{
  14. return 'It\'s empty!';
  15. }
  16. }
  17.  
  18. public function __get($name) {
  19. if ($this->modules[$name]) {
  20. return $this->modules[$name];
  21. }else{
  22. return false;
  23. }
  24. }
  25.  
  26. static public function create() {
  27. static $handle;
  28. if (!isset($handle)) {
  29. $handle = new view();
  30. }
  31. return $handle;
  32. }
  33.  
  34. public function _load($name) {
  35. if ($this->$name) {
  36. return $this->$name;
  37. }else{
  38. $temp = __CLASS__ .'_'. $name;
  39. if (file_exists('modules/'.$temp.'.php')) {
  40. include_once('modules/'.$temp.'.php');
  41. return $this->$name = new $temp;
  42. }else{
  43. return false;
  44. }
  45. }
  46. }
  47.  
  48. public function save($text) {
  49. return $this->content .= $text;
  50. }
  51.  
  52. public function view() {
  53. if ($this->content) {
  54. return $this->content;
  55. }else{
  56. return false;
  57. }
  58. }
  59.  
  60. }
  61.  
  62. ?>


Przykładowy moduł:
  1. <?php
  2.  
  3. class view_template {
  4.  
  5. private $vars;
  6. private $values;
  7. private $content;
  8.  
  9. public function __toString() {
  10. return $this->parse();
  11. }
  12.  
  13. public function add($var, $value) {
  14. $this->vars[] = $var;
  15. $this->values[] = $value;
  16. return true;
  17. }
  18.  
  19. public function _load($text) {
  20. $this->content = $text;
  21. }
  22.  
  23. public function parse() {
  24. if ((is_array($this->vars)) && (is_array($this->values))) {
  25. return str_replace($this->vars, $this->values, $this->content);
  26. }else{
  27. return 'Error';
  28. }
  29. }
  30.  
  31. }
  32.  
  33. ?>


Mam nadzieję, że to mniej więcej rozjaśni mój problem. ;d
megawebmaster
I jak masz zamiar tego użyć? Bo mimo, że się wgłębiłem, to nie mogę znaleźć się w Twoim kodzie... Pokaż przykładowy kod użycia proszę.

BTW. Od tego są tablice asocjacyjne, żeby nie robić takich diabełków jak to:
  1. public function add($var, $value) {
  2. $this->vars[] = $var;
  3. $this->values[] = $value;
  4. return true;
  5. }


tylko uprościć sobie:

  1. public function add($var, $value) {
  2. $this->vars[$var] = $value;
  3. return true;
  4. }


EDIT: Potem sobie korzystasz z array_keys()
Fifi209
Cytat(megawebmaster @ 15.08.2009, 22:17:48 ) *
I jak masz zamiar tego użyć? Bo mimo, że się wgłębiłem, to nie mogę znaleźć się w Twoim kodzie... Pokaż przykładowy kod użycia proszę.

Masz w pierwszym poście...
Cytat(megawebmaster @ 15.08.2009, 22:17:48 ) *
BTW. Od tego są tablice asocjacyjne, żeby nie robić takich diabełków jak to:

Jak już wspomniałem kod jest pisany na kolanie, tylko w celach "testowych". (chciałem zobaczyć jak to będzie działało)
megawebmaster
No to najprostszym rozwiązaniem jest przekazanie do obiektu view_template przy ładowaniu samego siebie ($this) i w ten sposób uzyskasz dostęp do metod klasy view. Dzięki temu możesz sobie dodać zapisywanie, albo nawet bezpośrednie dodawanie do zmiennej $content klasy view w metodach dołączonych. To takie najprostsze rozwiązanie. Inne rozwiązanie to zrobienie to tak jak napisał ktoś wcześniej - wzorzec adapter - i ładowanie modułów, ale ich obsługa bezpośrednio w klasie view. To tyle wymyśliłem na kolanie.

P.S. Ewentualnie w obiektach modułów można wywołać w konstruktorze modułu view::create() i pobrać instancję klasy view.
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.