Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Klasa Configurator
Forum PHP.pl > Forum > PHP > Pro > Archiwum Pro
Prph
Witam,

Pisze framework do wlasnych potrzeb. Planuje napisac PROSTA i uzyteczna klase do ladowania konfiguracji.

Moze macie z tym doswiadczenie?
Moje rozwiazanie w szkicu jest nastepujace:

  1. <?php
  2.  
  3. class Configurator
  4. {
  5.  
  6. public function getAttribute()
  7. {
  8. $aConfig = array // Tablica asocjacyjna konfiguracji
  9.  (
  10.  'Actions' => array
  11. (
  12. 'Error404' => array
  13. (
  14. 'security' => false,
  15. 'nextModule' => 'Test'
  16. ),
  17.  
  18. 'Default' => array
  19. (
  20. 'security' => false,
  21. 'nextModule' => 'Default2'
  22. )
  23. )
  24.  );
  25.  
  26. if(func_num_args() == 0) // Dostep do konfugiracji uzyskuje sie przez
  27. return null;  // liste parametrow do funkcji.
  28.  // Kolejne parametry, to kolejne węzły konfiga
  29.  
  30. $aArgs = func_get_args();
  31.  
  32. $aCurrentConfig = $aConfig;
  33.  
  34. foreach($aArgs as $sKey => $sAttributeName) // przechodzac przez kolejne elementy, zmieniamy "obecny węzeł"
  35. {
  36. if(isset($aCurrentConfig[$sAttributeName]))
  37. $aCurrentConfig = $aCurrentConfig[$sAttributeName];
  38. else
  39. return null; // jeżeli nie znalaziono podanego węzła, zwracamy null
  40. }
  41.  
  42. return $aCurrentConfig; // niby to array, ale jezeli chcemy dokladnie
  43. // wartosc ostatniego wezla, zwrocona zostanie
  44. // nie tablica, ale inna zmienna.
  45. }
  46.  
  47. public function hasAttribute() {}
  48. public function setAttribute() {}
  49.  
  50. public function saveConfiguration() {}
  51. }
  52.  
  53. $oConfigurator = new Configurator();
  54.  
  55. echo $oConfigurator->getAttribute('Actions', 'Default', 'nextModule');
  56. // zwroci "Default2".
  57.  
  58. ?>


Bede wdzieczny za wskazowki, radu, etc. Pozdrawiam, Adrian.
NuLL
http://ez.no/doc/components/view/1.0.1/(fi...figuration.html - polecam, ja z tej klasy korzystam od czasu kiedy pierwszy publiczny release byl :]
Cysiaczek
Osobiście, to mi się ten array nie podoba. Może jednak składowe obiektu konfiguracji zamiast arraya?
Potem nakład pracy może się zwrócic.
NuLL
Dostep tablicowy jest szybszy - nie ma sensu tworzyc otoczki obietowej wg mnie.
Prph
No i jeszcze mozna wziac pod uwage to, ze niekoniecznie ten array pojawi sie w klasie. Odczytujac duze pliki lepiej bedzie na bierzaco pobierac dane, chociaz kto wie winksmiley.jpg
Cysiaczek
A może pobierac dane tylko wtedy, gdy będzie taka potrzeba? Np. 'któś cóś' zmieni winksmiley.jpg
NuLL
Duzych plikow konfiguracyjnych sie nie tworzy. Duze pliki dzieli sie na mniejsze - lepiej przeczytac dwa mniejsze pliki niz jeden duzy.
Cysiaczek
No widzisz NuLL. Może jednak obiekty, bo zarządzac będzie łatwiej (np tymi mniejszymi plikami w szerszym kontekście)
NuLL
Pokaz mi przewage obiektow nad tablicami snitch.gif Plusy programowania obiektowego znam, ale nie lubie ani wywazac otwartych drzwi ani tworzyc przerostu formy nad trescia.
Prph
Odnosnie obiektowego podejscia. Chodzi np o uzyskanie:

$oConf->Actions->Error404->nextModule ?

A da sie tak?

Pozdrawiam.
NuLL
Prph - da sie. Tylko po co ?

Poczytaj o __get w manualu w czesci poswieconej OOP dla PHP5 tongue.gif
Prph
__get znam, ale umiem tylko jeden poziom odczytac. A co w przypadku ->Actions->Error->cos->innego?

Osobiscie tez wydaje mi sie metoda za lepsze rozwiazanie.
hwao
zagniezdzasz pare obiektow i jedziesz po koleji po nich (wracaja je pokoleji)
Prph
Tak myslalem.... Beznadziejnie winksmiley.jpg Ma byc prosta smile.gif

Narazie wyglada tak: (w zasadzie nic nie zmienialem)

  1. <?php
  2.  
  3. class PHPConfigurator implements IConfigurator
  4. {
  5.  
  6. private $_aConfiguration;
  7. private $_sConfigurationFileName;
  8.  
  9. public function __construct($sConfigurationFileName)
  10. {
  11. $this->_aConfiguration = array();
  12.  
  13. if(!is_readable($sConfigurationFileName))
  14. throw new ConfiguratorException('Can not open given configuration file ' . $sConfigurationFileName);
  15.  
  16. require_once($sConfigurationFileName);
  17.  
  18. if(!isset($_aConfiguration))
  19. throw new ConfiguratorException('Configuration array does not exist');
  20.  
  21. $this->_aConfiguration = $_aConfiguration;
  22. }
  23.  
  24. public function getAttribute()
  25. {
  26. if(func_num_args() == 0)
  27. return null;
  28.  
  29. $aArgs = func_get_args();
  30.  
  31. $aCurrentConfig = $this->_aConfiguration;
  32.  
  33. foreach($aArgs as $sKey => $sAttributeName)
  34. {
  35. if(isset($aCurrentConfig[$sAttributeName]))
  36. $aCurrentConfig = $aCurrentConfig[$sAttributeName];
  37. else
  38. return null;
  39. }
  40.  
  41. return $aCurrentConfig;
  42. }
  43.  
  44. public function hasAttribute()
  45. {
  46. return false;
  47. }
  48.  
  49. public function setAttribute() {}
  50.  
  51. public function saveConfiguration() {}
  52. }
  53. ?>


Do tego dodalem metode do klasy akcji:

  1. <?php
  2. public function getConfigurator()
  3. {
  4. if(isset($this->_oConfigurator))
  5. return $this->_oConfigurator;
  6. else
  7. {
  8. $sConfigurationFileName = $this->_getController()->getModuleDir() . _DIR_APPLICATION_MODULES_CONFIGURATIONS . get_class($this) . 'Configuration.php';
  9.  
  10. $this->_oConfigurator = new PHPConfigurator($sConfigurationFileName);
  11.  
  12. return $this->_oConfigurator;
  13. };
  14. }
  15. ?>


Mysle, ze spisze sie ta klasa winksmiley.jpg

Jakies uwagi?

Adrian.
arturwow
Ja na potrzeby swojego frameworka popełniłem takie coś

  1. <?php
  2.  
  3.  
  4. /**
  5.  * Moduł jądra do zarządzania konfiguracją
  6.  *
  7.  */
  8. class cConfig implements ArrayAccess
  9. {
  10. private $configuration = array();
  11.  
  12. /**
  13.  * Ładuje plik konfiguracyjny
  14.  *
  15.  * @param string $fileName
  16.  */
  17. public function load($fileName)
  18. {
  19. $data = new cConfigFile($fileName);
  20. $this -> configuration[$data -> section] = &$data;
  21. }
  22.  
  23. /**
  24.  * Implementacja ArrayAccess
  25.  */
  26. public function offsetExists($key)
  27. {
  28. return (key_exists($key, $this -> configuration));
  29. }
  30. /**
  31.  * Implementacja ArrayAccess
  32.  */
  33. public function &offsetGet($key)
  34. {
  35. return $this -> configuration [$key];
  36. }
  37. /**
  38.  * Implementacja ArrayAccess
  39.  */
  40. public function offsetSet($key, $value)
  41. {
  42. $this -> configuration [$key] = $value;
  43. }
  44. /**
  45.  * Implementacja ArrayAccess
  46.  */
  47. public function offsetUnset ($key)
  48. {
  49. unset($this -> configuration [$key]);
  50. }
  51. }
  52.  
  53. class cConfigFile implements ArrayAccess
  54. {
  55. private $sectionName;
  56. private $fileName;
  57. /**
  58.  * Tablica zawierająca konfigurację
  59.  *
  60.  * Tablica może być 'wielopoziomowa'
  61.  * 
  62.  * @var array
  63.  */
  64. private $params = array();
  65.  
  66. /**
  67.  * Konstruktor. Wczytuje plik konfiguracyjny do obiektu
  68.  *
  69.  * Sprawdza najpierw czy plik może nie jest już w cache,
  70.  * wtedy można ominąć powolne parsowanie pliku XML. 
  71.  * W przeciwnym wypadku wczytujemy plik i uruchamiamy parser
  72.  * XML.
  73.  * Użyłem fopen+fread, ponieważ z mojego benchmarka wyniklo, 
  74.  * że dla małych plików file_get_contens() jest wolniejsze.
  75.  *
  76.  * 
  77.  * @param string $fileName
  78.  * @todo działanie, gdy nie można odczytać pliku.
  79.  * 
  80.  */
  81. public function __construct($fileName)
  82. {
  83. if (is_readable($fileName))
  84. {
  85. $app = cKernel::getInstance();
  86. $cacheID = $app['cache'] -> makeFileID ('ConfigFile', $fileName);
  87. if ($app['cache'] -> cacheExists($cacheID) && _PHPEAX_CACHE_ON)
  88. {
  89. $data = &$app['cache'] -> fromCache($cacheID);
  90. } 
  91. else 
  92. {
  93. $file_handler = fopen($fileName,'r');
  94. $file = fread($file_handler,filesize($fileName));
  95. fclose($file_handler);
  96. $data = &$app['xml'] -> unserialize($file);
  97. if (_PHPEAX_CACHE_ON)
  98. {
  99. $app['cache'] -> toCache($cacheID, &$data);
  100. }
  101. }
  102. $this -> sectionName = $data ['section'];
  103. $this -> params = &$data ['config'];
  104. $this -> fileName = $fileName;
  105. }
  106. }
  107. /**
  108.  * Implementacja ArrayAccess
  109.  */
  110. public function offsetExists($key)
  111. {
  112. return (key_exists($key, $this -> params));
  113. }
  114. /**
  115.  * Implementacja ArrayAccess
  116.  */
  117. public function &offsetGet($key)
  118. {
  119. return $this -> params [$key];
  120. }
  121. /**
  122.  * Implementacja ArrayAccess
  123.  */
  124. public function offsetSet($key, $value)
  125. {
  126. $this -> params [$key] = $value;
  127. }
  128. /**
  129.  * Implementacja ArrayAccess
  130.  */
  131. public function offsetUnset ($key)
  132. {
  133. unset($this -> params [$key]);
  134. }
  135. /**
  136.  * Zapisuje konfigurację do pliku
  137.  * 
  138.  * Do przetestowania.
  139.  *
  140.  */
  141. public function save()
  142. {
  143. $app = cKernel::getInstance();
  144. $config = array();
  145. $config['section'] = $this -> sectionName;
  146. $config['config'] = $this -> params;
  147. $serialized = $app['xml'] -> serialize($config);
  148. file_put_contents($this -> fileName, $serialized);
  149. }
  150. /**
  151.  * Przeciążenie właściwości
  152.  * 
  153.  * cConfigFile::sectionName nie jest public, ponieważ
  154.  * ma być tylko do odczytu.
  155.  *
  156.  * @param string $property
  157.  * @return unknown
  158.  */
  159. public function __get($property)
  160. {
  161. switch (strtolower($property))
  162. {
  163. case 'section':
  164. return $this -> sectionName;
  165. break;
  166. default:
  167. return null;
  168. break;
  169. }
  170.  
  171. }
  172. }
  173. ?>


Przykładowy plik konfiguracyjny:
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xml>
  3.      <section>global</section>
  4.      <config>
  5.            <homedir>/phpEAX/</homedir>
  6.            <language>
  7.                  <encoding>UTF-8</encoding>
  8.            </language>
  9.            <template>default</template>
  10.            <site>
  11.                  <title>..:: eax.pl Center ::..</title>
  12.                  <author>Artur Roszczyk</author>
  13.            </site>
  14.      </config>
  15. </xml>



Niedługo pokażę światu zalążek tego frameworka (jest już całkiem sporo winksmiley.jpg ), tylko czekam na maila od autora OPT, ponieważ jest on wykorzystywany w moim partactwie :roll2:

A wogóle to witam smile.gif Jest to mój pierwszy post na tym forum smile.gif
Ociu
Najogólniej to zrobiłem to tak:
  1. <?php
  2. class ZConfig implements iConfig
  3. {
  4.  
  5. private $configuration;
  6.  
  7. public function __construct()
  8. {
  9.  
  10.  
  11.  
  12. }
  13.  
  14. public function setConfig( $config )
  15. {
  16.  
  17. $this->configuration = $config;
  18.  
  19. }
  20.  
  21. public function getConfig()
  22. {
  23.  
  24. return $this->configuration;
  25.  
  26. }
  27.  
  28. public function receive( $name )
  29. {
  30.  
  31. return $this->configuration->get( $name );
  32.  
  33. }
  34.  
  35. public function __get( $name )
  36. {
  37.  
  38. return self::receive( $name );
  39.  
  40. }
  41.  
  42. public function attach( $name, $value ) 
  43. {
  44.  
  45. if( get_class($this->configuration) == 'ZLazyConfiguration' || get_class($this->configuration) == 'ZPHPConfiguration' )
  46. {
  47.  
  48. $this->configuration->attach( $name, $value );
  49.  
  50. }
  51.  
  52. }
  53.  
  54. public function __set( $name, $value )
  55. {
  56.  
  57. self::attach( $name, $value );
  58.  
  59. }
  60.  
  61.  
  62. }
  63. ?>


Noi najprostrzy komponent:
  1. <?php
  2. class ZLazyConfiguration implements iConfigurationComponent {
  3.  
  4. private $map = array();
  5.  
  6. public function attach( $sIndex, $sValue ) 
  7. {
  8.  
  9. if( !self::exists( $sIndex ) )
  10. {
  11. $this->map[ $sIndex ] = $sValue;
  12.  
  13. return true;  
  14. } else {
  15.  
  16. return false;
  17.  
  18. }
  19.  
  20. }
  21.  
  22. public function get( $sIndex ) 
  23. {
  24.  
  25. if( self::exists( $sIndex ) ) 
  26. {
  27.  
  28. return $this->map[ $sIndex ];
  29.  
  30. } else
  31. {
  32.  
  33. return false;
  34.  
  35. }
  36.  
  37. }
  38.  
  39. private function exists( $sIndex )
  40. {
  41.  
  42. return isset( $this->map[ $sIndex ] );
  43.  
  44. }
  45. }
  46. ?>


Saluto, Wojtek
Ludvik
Co do powyższego kodu - dziwnie według mnie napisany. Dziwi mnie wykorzystanie modyfikatorów dostępu, a pominięcie kontroli typów, która nie zmieni nic w kwestii przenośności tego kodu. Poza tym wywołujesz metody nie-statyczne ze statycznego kontekstu
  1. <?php
  2. public function receive( $name );
  3.  
  4. public function __get( $name ) {
  5. return self::receive( $name );
  6. }
  7. ?>


Co do zalet pisania własnych kontenerów, to dają one nieco większą kontrolę niż tablice. Są wygodniejsze, chociażby przez fakt przekazywania przez referencje. Rozumiem NuLL, że nie kopiujesz całej tablicy przy przekazywaniu i zwracaniu jej z funkcji? Różnice przy dostępie do obiektu i tablicy są według mnie minimalne...
Strzałek
Ja skorzystałem z ArrayAccess smile.gif

  1. <?php
  2. $config = Config::get('news'); //plik: config/news.ini
  3. echo $config['news_per_page'];
  4. ?>
bigZbig
A ja proponuję zapoznać się z Zend_Config.

--- edit ---

@NuLL - tak na marginesie - stworz sobie uniwersalna klase typu Data Transfer Object implementującą interfejsy ArrayAccess oraz IteratorAggregate, dodaj do tego metody magiczne __get i __set i mozesz stworzyc sobie wielopoziomowy konfig dający dostep do danych zarowno w sposob charakterystyczny dla tablic, jak i dla obiektow. Pytasz po co to? Ja na przyklad uzywam w swoich projektach czegos takiego jak rejestrator obiektow, ktory umozliwia dostep do wybranych obiektow (oDb, oTpl, oLang, oUser, oConf) w dowolnym miejscu aplikacji.
Ociu
Cytat(Ludvik @ 10.07.2006, 10:43 ) *
Co do powyższego kodu - dziwnie według mnie napisany. Dziwi mnie wykorzystanie modyfikatorów dostępu, a pominięcie kontroli typów, która nie zmieni nic w kwestii przenośności tego kodu. Poza tym wywołujesz metody nie-statyczne ze statycznego kontekstu


Może Cie to dziwić. Mnie tez to dziwi smile.gif Kod jest pisany z palca z czytelnymi odstępami po półrocznej przerwie w pisaniu w PHP5. smile.gif
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-2024 Invision Power Services, Inc.