Założeniem biblioteki jest łatwość konfiguracji zachowania danej klasy. Standardowo, w większości bibliotek/frameworków istnieją odpowiednie wartości przypisane do danego ustawienia.
Tutaj tak nie ma, chciałem wyróżnić, że dana wartość pochodzi z ustawień a inna jest po prostu przetwarzana – powstała wartość:
static private $_classSettings = array();Dlaczego statyczna? Niezależnie czy dana klasa ma metody wyłącznie statyczne, czy też posługujemy się obiektami danej klasy – ustawiamy raz i zapominamy.
Oczywiście należy pamiętać o tym, że będziemy potrzebowali zmienić ustawienia w trakcie działania skryptu. Tak więc obsługa zmiany również powinna być dołączona.
Do obsługi ustawień potrzebować będziemy dwóch metod: wprowadzania ustawień i ich odczytu. Ustawienia są ściśle zdefiniowane w $_classSettings, podanie innego klucza tablicy powinno nas jakoś informować o błędzie (“literówkę”). Metody prezentują się następująco:
Przekazywany parametr jako tablica np:
klasa::settings(array('sciezka'=>'/sciezka/do/zapisu'));
static public function settings($classSettings)
{
if (!is_array($classSettings)) {
return false;
}
foreach ($classSettings as $key=>$row) {
if (array_key_exists($key, self::$_classSettings)) {
self::$_classSettings[$key] = $row;
} else {
// rzutuj wyjątek lub zapisz błąd o braku klucza w ustawieniach
// przydatne gdy ktoś zrobi “literówkę”
}
}
return true;
}
Jako parametr podajemy nazwę klucza w tablicy ustawień, którego wartość chcemy poznać, jeżeli chcemy pobrać całą tablicę nie podajemy żadego parametru.
$_wszystkieUstawienia = klasa::getSetting();
static public function getSetting($setting=null)
{
// jeśli chcemy pobrać całą tablicę ustawień
if ($setting===null) {
return self::$_classSettings;
}
if (! array_key_exists($setting, self::$_classSettings)) {
// rzutuj wyjątek lub zapisz błąd o braku klucza w ustawieniach
// przydatne gdy ktoś zrobi “literówkę”
return "setting {$setting} not defined";
}
return self::$_classSettings[$setting];
}
To by było na tyle. Ale wszystko można usprawnić. Jeżeli dane metody występują w każdej klasie, dlaczego nie utworzyć klasy settings i dziedziczyć po niej? Kod wyglądałby następująco
class Settings
{
static protected $_classSettings = array();
static public function setting($classSettings)
{
// tu ten sam kod co wyżej
}
static public function getSetting($setting=null)
{
// tu ten sam kod co wyżej
}
}
I każda klasa która wymaga ustawień, dziedziczyłaby po niej i wystarczyłoby wprowadzić wyłącznie tablicę ustawień.
class test extends Settings
{
static protected $_classSettings = array('path'=>'path/to/file');
}
I możemy pobrać ustawienia klasy test
echo test::getSetting('path');
Obojętnie od rodzaju wersji PHP nie będzie to działać – nie ma czegoś takiego, jak statyczne dziedziczenie. Na logikę powinno, ale niestety. Jednakże w wersji 5.3 wprowadzono coś takiego jak Late Static Binding Sposób wprowadzania kodu jest inny, ale zapewni to co chcieliśmy osiągnąć.
Kod w użyciu LSB wyglądać będzie następująco:
class Settings
{
static protected $_classSettings = array();
static public function setting($classSettings)
{
if (!is_array($classSettings)) {
return false;
}
foreach ($classSettings as $key=>$row) {
if (array_key_exists($key, static::$_classSettings)) {
static::$_classSettings[$key] = $row;
} else {
/*
rzutuj wyjątek lub zapisz błąd o braku klucza w ustawieniach
przydatne gdy ktoś zrobi “literówkę”
*/
}
}
return true;
}
static public function getSetting($setting=null)
{
/*
jeśli chcemy pobrać całą tablicę ustawień
*/
if ($setting===null) {
return static::$_classSettings;
}
if (! array_key_exists($setting, static::$_classSettings)) {
// /*
// rzutuj wyjątek lub zapisz błąd o braku klucza w ustawieniach
// przydatne gdy ktoś zrobi “literówkę”
// */
return "setting {$setting} not defined";
}
return static::$_classSettings[$setting];
}
}
Proszę zwrócić uwagę na wyraz static zamiast self. Ta zmiana umożliwi nam poprawne działanie, ale tylko w PHP5.3 i wyższych.
I tutaj należy wybrać, dziedziczenie czy też pisanie wszędzie metod obsługujących ustawienia klasy. Wybrałem drugie rozwiązanie, gdyż wersja 5.3 jest praktycznie nie dostępna na serwerach hostingowych. A biblioteka ma działać praktycznie wszędzie.
Ustawienia możemy przechowywać w pliku np ini o następującej budowie:
[nazwa klasy]
ustawienie1 = "test"
ustawienie2 = true
ustawienie3 = 3
[nazwa klasy 2]
.
.
.
I wczytywać przez funkcję:
function _config($file, $throwException=false)
{
if (!file_exists($file) and $throwException) {
throw new exception(sprintf('File %s not exists', $file));
}
$_settings = parse_ini_file($file, true);
foreach ($_settings as $_class=>$_classSettings) {
if (!class_exists($_class, false) and $throwException) {
throw new exception(sprintf('Class %s not exists', $_class));
}
if (!method_exists($_class, 'settings') and $throwException) {
throw new exception(
sprintf('Settings method in class %s not exists', $_class)
);
}
foreach ($_classSettings as $key=>$val) {
if (strtolower($val)==="true") {
$_classSettings[$key]= true;
} elseif (strtolower($val)==="false") {
$_classSettings[$key]= false;
} elseif (strtolower($val)==="null") {
$_classSettings[$key]= null;
}
}
call_user_func(array($_class, 'settings'), $_classSettings);
}
}
Komentarze podlegają moderacji, nie dopuszczam komentarzy spamujących, z wyzwiskami, wulgaryzmami, oszczerstwami. Rozumiem przez to również nie akceptowanie komentarzy, których treść jest prawnie zabroniona. Pozostałe komentarze, nawet takie które będą sprzeczne z moimi poglądami są akceptowane. Należy czekać na akceptację, każdy komentarz zostanie sprawdzony przeze mnie a następnie ukaże się na stronie.
Niestety, takie rozwiązanie jest wybitnie niepraktyczne. Już to przerabiałem spory kawałek czasu temu przy okazji tworzenia Open Power Libs 2.0 i do dziś odbija mi się to czkawką. Po pierwsze, używasz do tego elementów statycznych, czyli już na wejściu utrudniasz sobie testowanie i wprowadzasz elementy niedeterminizmu, które mogą być źródłem podobnych problemów, jakie powoduje "global". Po drugie, Twoja funkcja do ładowania konfiguracji też jest niepraktyczna, bowiem wymaga uprzedniego załadowania wszystkich możliwych klas nawet, jeśli ich nie używamy, gdyż inaczej oberwiemy wyjątkiem. Dobrym, sprawdzonym rozwiązaniem jest idea wstrzykiwania zależności. PS. Masz u mnie minusa za nałożenie limitu min. 5 znaków na długość nicka, który jest idiotyczny, jako że jest całkiem sporo osób, które mają czteroliterowe nicki, a trzyliterowe takie, jak mój, też się trafiają.