Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Sposob na przechowywanie parametrow w obiekcie
Forum PHP.pl > Forum > PHP > Object-oriented programming
Prph
Witam,

Zastanawiam sie ostatnio, co jest lepszym rozwiazaniem w perspektywie wiekszej aplikacji:

  1. <?php
  2. $aConfig['system']['db']['host'] = '127.0.0.1';
  3.  
  4. $oConfig = new Config($aConfig);
  5.  
  6. // Rozwiazanie 1.
  7. $host = $oConfig->system->db->host;
  8.  
  9. // Rozwiazanie 2.
  10. $host = $oConfig->get('system', 'db', 'host');
  11. ?>


Moim zdaniem pierwsze rozwiazanie jest 'ladniejsze' i duzo bardziej wygodne. No i zaczynaja sie schody:

  1. <?php
  2. $host = $oConfig->system->jakas_nieistniejaca_zmienna->host;
  3. // Zwroci NOTICE informuujace o tym, ze nastepuja odwolanie do nieistniejacego obi
    ektu - no bo zachowa sie jak: null->host;
  4.  
  5. $host = $oConfig->get('System', 'nieistneijaca_zmienna', 'host');
  6. // Zwroci po prostu null bez zadnego bladu.
  7. ?>


Ok. pojawia sie magiczne __isset(). Ale:

  1. <?php
  2. var_dump(isset($oConfig->host)); // zwroci false;
  3. var_dump(isset($oConfig->db->host)); // zwroci false, ale tak naprawde metoda __isset nie zostanie wywolana (?)
  4.  
  5. var_dump(isset($oConfig->db->cos->host)) // zwroci false i wyswietli Notice: odwolanie do nieistniejacego obiektu.
  6. ?>


Kod:

  1. <?php
  2. class ParametersHolder
  3. {
  4. private $_aParameters;
  5. private $_bValidIterationPointer;
  6.  
  7. public function __construct($aParameters = array())
  8. {
  9. foreach($aParameters as $sKey => $mValue)
  10. {
  11. if(is_array($mValue))
  12. $this->_aParameters[$sKey] = new ParametersHolder($mValue);
  13. else
  14. $this->_aParameters[$sKey] = $mValue;
  15. }
  16. }
  17.  
  18. public function __get($sParameter)
  19. {
  20. return isset($this->_aParameters[$sParameter]) ? $this->_aParameters[$sParameter] : null;
  21. }
  22.  
  23. public function __set($sParameter, $mValue)
  24. {
  25. if(is_array($mValue))
  26. $this->_aParameters[$sParameter] = new ParametersHolder($mValue);
  27. else
  28. $this->_aParameters[$sParameter] = $mValue;
  29. }
  30.  
  31. public function __isset($sParameter)
  32. {
  33. return isset($this->_aParameters[$sParameter]);
  34. }
  35. }
  36. ?>


Co o tum uwazacie? Moze macie lepszy sposob?

Adrian.
hwao
Swojego czasu pisalem arta na ten temat ->
http://hwao.be/blog/2006/06/18/konfiguracj...przechowywanie/

Cenne sa komentarze inych uzytkownikow
Prph
Klasa konfiguracji to akurat przyklad. Ta sama sytuacja wystepujue chociazby przy pobieraniu danych z widoku czy ich zapisywaniu.

A wiec jakie pomysly?
NuLL
Cytat
// Rozwiazanie 1.$host = $oConfig->system->db->host;// Rozwiazanie 2.$host = $oConfig->get('system', 'db', 'host');

A jaka to jest roznica questionmark.gif
Cytat
$host = $oConfig->system->jakas_nieistniejaca_zmienna->host;// Zwroci NOTICE informuujace o tym, ze nastepuja odwolanie do nieistniejacego obi
ektu - no bo zachowa sie jak: null->host;$host = $oConfig->get('System', 'nieistneijaca_zmienna', 'host');// Zwroci po prostu null bez zadnego bladu.

laugh.gif - poprostu nie potrafisz porzadnie programowac
Cytat
Ok. pojawia sie magiczne __isset(). Ale:

Z jakiego php korzystasz questionmark.gif
hwao
@NuLL zastanawiam się w takim razie, w jakim Ty języku programujesz... albo masz braki po prostu w php5.1...

Zeby nie byc golo slownym.
  1. <?php
  2. error_reporting( E_ALL | E_STRICT );
  3.  
  4. class Bar {
  5. public $foo = 'string';
  6.  
  7. public function __isset( $sString ) {
  8. echo 'Bar::'.$sString.' - nie istnieje!'."n";
  9. }
  10.  
  11. public function __unset( $sString ) {
  12. echo 'Bar::'.$sString.' - nie istniejąca właściwość, usunięta!'."n";
  13. }
  14. }
  15.  
  16.  
  17. echo '<pre>';
  18. $Bar = new Bar();
  19.  
  20. echo 'Bar::foo = '.$Bar->foo."n";
  21.  
  22. if( isSet( $Bar->foo ) ) {
  23. echo 'Bar::foo - Istnieje'."n";
  24. }
  25.  
  26. if( isSet( $Bar->foo2 ) ) {
  27. // Tego nie zobaczysz
  28. echo 'Bar::foo2 - Istnieje'."n";
  29. }
  30.  
  31. unset( $Bar->foo3 );
  32. echo '</pre>';
  33.  
  34. ?>


Efekt działania:
Kod
Bar::foo = string
Bar::foo - Istnieje
Bar::foo2 - nie istnieje!
Bar::foo3 - nie istniejąca właściwość usunięta!


Masz tutaj na wortalu komentarz nawet o tym:
http://wortal.php.pl/phppl/wortal/artykuly...zestrzenie_nazw
Tu masz jeszcze kurs dla poczatkujacych, w ktorym to jest omowione:
http://www.gajdaw.pl/php/obiekty-3.html

Dla taka nie wiedza w dodatku z takimi slowami
Cytat
laugh.gif - poprostu nie potrafisz porzadnie programowac

Jakoś dziwnie brzmia...

@Prph: Wg mnie najlepsze jest zastosowanie 2gie, tylko zeby byly tam wyjatki zwracane
Prph
Witam,

@NuLL: Zamiast sie nabijac, moze bys podal jakies rozwiazanie. Pokaz jak ty porzadnie programujesz.

Hwao: Dzieki za odpowiedz. Tez uwazam drugie rozwiazanie za lepsze i nawet wprowadzielm juz zmiany w kodzie. Troche myslalem nad zwracaniem wyjatku w chwili kiedy atrybut nie istnieje. Ale chyba wartosc null bedzie lepsza, bioroc pod uwage ze w szablonie zrobi np:

  1. <?php
  2. echo $this->lang('kontroler', 'akcja', 'errory', 'zly ID');
  3. ?>


Po prostu tego nie wyswietli.

bigZbig: Wlasnie na Zend_Config wzorowane jest rozwiazanie 1. Zend_Config chyba nie jest najlepszym rozwizaniem.

Pozdrawiam, Adrian.
hwao
Pierwsze rozwiazanie to jest poprostu zapychanie nie potrzebnie (imho) pamieci smile.gif jakby php mialo jakies narzedzie ktore sprawnie pozwala dostawac sie do danych w tablicy jak w obiekcie, to by bylo spoko - niestety chyba takowego nie ma..

Pisanie tego ma maticznych metodach to przerost formy nad trescia, duzo wygodniejsze jest 2 rozwiazanie. Proponowal bym zastanowic sie czy nie warto dodac tez parametr domyslny, jezeli nie ma wartosci to zwraca domyslna wartosc smile.gif
Prph
Tak, ktos juz mowil o twej wartosci domyslnej.

W tej chwili zwraca null. Jest to calkiem uzasadnione, jezeli uzyjemy rozwiazania w szablonach:

  1. <?php
  2. echo $this->get('moja zmienna');
  3. ?>


Taki efekt czesto jest pozadany (przynajmniej w moich aplikacjach).

Ponadto, gdy zwracane jest null, wygodnie robic:

  1. <?php
  2. $sMojaZmienna = $this->get('moja_zmienna');
  3.  
  4. if(!is_null($sMojaZmienna))
  5. {
  6. // zrob cos, bo zmienna ma wartosc!
  7. }
  8. ?>


Adrian.
NuLL
Cytat
@NuLL: Zamiast sie nabijac, moze bys podal jakies rozwiazanie. Pokaz jak ty porzadnie programujesz.

A prosze Cie bardzo biggrin.gif
Cytat
jakby php mialo jakies narzedzie ktore sprawnie pozwala dostawac sie do danych w tablicy jak w obiekcie, to by bylo spoko - niestety chyba takowego nie ma..

Chyba mozna sobie to napisac czy nie questionmark.gif snitch.gif
  1. <?php
  2.  
  3. class variableCollection
  4. {
  5. protected $data=array();
  6.  
  7. public function __construct(array$arr)
  8. {
  9. if(count($arr))
  10. {
  11. $this->data=$arr;
  12. }
  13. }
  14.  
  15. public function __get($name)
  16. {
  17. if(isset($this->data[$name]))
  18. {
  19. if(is_array($this->data[$name]))
  20. {
  21. $this->data[$name]=new variableCollection($this->data[$name]);
  22. }
  23.  
  24. return $this->data[$name];
  25. }
  26.  
  27. return false;
  28. }
  29. }
  30.  
  31. $config['system']['db']['host'] = '127.0.0.1';
  32.  
  33. $configObj=new variableCollection($config);
  34.  
  35. var_dump(isset($configObj->host));
  36. var_dump(isset($configObj->system->db->cos->host));
  37. var_dump(isset($configObj->db->host));
  38.  
  39. ?>

3 x FALSE - to wszystko ode mnie. FALSE mozna sobie zmienic na NULL w zaleznosci od potrzeby guitar.gif

Ta klaska tutaj napisan to wstep ;] - powinno byc implements ArrayAccess,Countable,Iterator + plus pare innych etod ale pozostawiam do rozwazenia naszym guru programowania obiektowego winksmiley.jpg PHP5 isn't it questionmark.gif biggrin.gif
Prph
  1. <?php
  2. ?>


Ok, widze u siebie blada. Zwraca null zamiast false.

@NuLL: No nic nowego oprocz tego false nie napisales, wiec kozak taki nie jestes winksmiley.jpg Ale dzieki wielkie - zwracanie null jest w tym przypadku bladem.

Pozdrawiam, Adrian.


Edit:

A jednak to nie dziala. Przedstawiam ponizszy kod i wynik:

  1. <?php
  2.  
  3.  
  4. class variableCollection
  5. {
  6. protected $data=array();
  7.  
  8. public function __construct(array$arr)
  9. {
  10. if(count($arr))
  11. {
  12. $this->data=$arr;
  13. }
  14. }
  15.  
  16. public function __get($name)
  17. {
  18. if(isset($this->data[$name]))
  19. {
  20. if(is_array($this->data[$name]))
  21. {
  22. $this->data[$name]=new variableCollection($this->data[$name]);
  23. }
  24.  
  25. return $this->data[$name];
  26. }
  27.  
  28. return false;
  29. }
  30. }
  31.  
  32. $config['system']['db']['host'] = '127.0.0.1';
  33.  
  34. $configObj=new variableCollection($config);
  35.  
  36. var_dump(isset($configObj->host));
  37. var_dump(isset($configObj->system->db->cos->d->d->d->d->host));
  38. var_dump(isset($configObj->db->host));
  39.  
  40. ?>


Wynik:

bool(false)
Notice: Trying to get property of non-object in /home/adrian/public_html/p.php on line 38

Notice: Trying to get property of non-object in /home/adrian/public_html/p.php on line 38

Notice: Trying to get property of non-object in /home/adrian/public_html/p.php on line 38

Notice: Trying to get property of non-object in /home/adrian/public_html/p.php on line 38
bool(false) bool(false)


No i co?

Adrian.
Apo
Błedy wywala bo musisz zwracać obiekt $this w metodzie. Spróbuj:

  1. <?php
  2. //...
  3. public function __construct(array$arr)
  4. {
  5. if(count($arr))
  6. {
  7. $this->data=$arr;
  8. }
  9. return $this;
  10. }
  11. //...
  12. ?>


Pozdrawiam
Prph
Yyy, a co ma piernik do wiatraka? Przeciez te blady sa generowane przez get. Jest na to sposob, ale bardzo glupi. Zamiast null zwraca sie new self.

A poza tym, return $this w konstruktorze jakos smiesznie wyglada winksmiley.jpg To tak jakby konstruktor mial zwrocic cos innego niz obiekt klasy winksmiley.jpg

Adrian.
NuLL
W sumie troche bubla napisalem - lepiej byloby to tak napisac
  1. <?php
  2.  
  3.  
  4. class variableCollection
  5. {
  6. protected $data=array();
  7.  
  8. public function __construct(array$arr)
  9. {
  10. if(count($arr))
  11. {
  12. $this->data=$arr;
  13. }
  14. }
  15.  
  16. public function __get($name)
  17. {
  18. if(isset($this->data[$name]))
  19. {
  20. if(!($this->data[$name] instanceof variableCollection ))
  21. {
  22. $this->data[$name]=new variableCollection($this->data[$name]);
  23. }
  24.  
  25. return $this->data[$name];
  26. }
  27.  
  28. throw new Exception("$name is not aviable");
  29. }
  30. }
  31.  
  32. $config['system']['db']['host'] = '127.0.0.1';
  33.  
  34. $configObj=new variableCollection($config);
  35.  
  36. try
  37. {
  38. var_dump(isset($configObj->host));
  39.  
  40. echo "<br>";
  41.  
  42. var_dump(isset($configObj->system->db->cos->host));
  43.  
  44. echo "<br>";
  45.  
  46. var_dump(isset($oConfig->db->host));
  47.  
  48. }catch(Exception $e)
  49. {
  50. echo $e->getMessage();
  51. }
  52.  
  53. ?>

I jeszcze mamy ladnie dodane wyjatki smile.gif
Prph
No teraz jest ok, ale jak mam uzywac try, catch, to wole napisac metode get() ze zmienna lista parametrow.

Adrian.
DjKermit
Sory za odgrzewanie kotletów ale zastanawiałem się po co i dlaczego wyjątki skoro można tak:
  1. <?php
  2. public function __get($name) {
  3. if(isset($this->data[$name])) {
  4. if(!($this->data[$name] instanceof self) && is_array($this->data[$name] )) {
  5. $this->data[$name]=new self($this->data[$name]);
  6. }
  7. return $this->data[$name];
  8. }
  9. return new self(array());
  10. }
  11. ?>

IMO to chyba lepsze rozwiązanie bo nie dostaniemy błędu, nie przerwiemy aplikacji tylko dostaniemy pusty obiekt.
Aczkolwiek mogę się mylić i będę wdzięczny za odzew.
Hacker
Odgrzane to ja jeszcze podgrzeje.
zrobiłbym podobnie jak DjKermit z tym, że zamiast zwracać za każdym razem nowy pusty obiekt, dałbym statyczne pole z pustym obiektem, który bym zwracał. Problem jest jedynie taki, że zamiast null dostajemy ten obiekt.
siemakuba
To ja też do odgrzania się przyczynię.

U siebie stosuję inne rozwiązanie, jeżeli chodzi o przechowywanie zmiennych, zbliżone do drugiego sposobu z pierwszego posta Adriana:

  1. <?php
  2. $Config->Set('system.db.host', '127.0.0.1');
  3. $Config->Get('system.db.host');
  4. ?>


system.db.host tłumaczone jest w funkcjach Get / Set na tablicę:
  1. <?php
  2. $arr['system']['db']['host'];
  3. ?>


Jak dla mnie rozwiązanie super wygodne.
Nie jestem mastah PHP5 i wszystkich rozwiązań związanych z jego obiektowością, ale czy potrzebne aż takie kombinacje? U mnie działa to prosto: Get pobiera co trzeba a jeżeli na którymś poziomie ścieżki nie ma odpowiedniej wartości (klucza w tablicy) zwraca false.

Całe to rozwiązanie stosuję w kilku miejscach, tworząc sobie metody Get i Set w klasach w których ich potrzebuję. Przykładowo:

  1. <?php
  2. class SessionHandler
  3. { 
  4. // ...
  5. function Get($path)
  6. {
  7. return ArrayPath::Get($path, $this->values);
  8. }
  9.  
  10. function Set($path, $value)
  11. {
  12. return ArrayPath::Set($path, $value, $this->values);
  13. }
  14. }
  15. ?>


Chyba że przedstawione przez was rozwiązania mają jakieś dodatkowe plusy, dla mnie w tej chwili niewidoczne.

pozdr.
DeyV
a ja się zastanawiam, dlaczego taka obawa przed stosowaniem wyjątków.

Konieczność używania try - catch ? Po co?

Przecież w tym przykładzie wyjątek pokazuje ewidentny błąd programisty - odwołanie się do nieistniejącej cechy w konfiguracji. Taki błąd powinien zostać wyłapany od razu, a więc wyjątek z całym trace powinien zostać jak najszybciej wyświetlony.
Sedziwoj
jak użyjesz throw i ktoś tego nie wyłapie to też wywali 'na ekran', a również przy nie wyłapaniu zatrzyma resztę skryptu. A poziom blokowania wykonania strony będzie w tym wydaniu z throw lepszy, bo i tak nie wykonasz dalszego kodu który jest zależny, ale reszta nie zależnego przy wyłapaniu będzie działać.
LBO
Mi się podoba mechanizm configu w Agavi.

Wyglądało to mniej więcej tak (dla twojego przykładu):

  1. <?php
  2. AgaviConfig::get('system.db.host');
  3. ?>
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.