Programując w dowolnym współcześnie wykorzystywanym języku na pewno zdarzyło Wam się korzystać z tzw. flag. Flaga, to nic innego niż stała wartość zapisana pod odpowiednim identyfikatorem. Jedną z szerzej stosowanych możliwości jest użycie ich jako komunikatów - numerów lub identyfikatorów np. błędów. W dzisiejszym wpisie pokażę pewien ciekawy sposób na przekazywanie bardziej zrozumiałych informacji dla użytkownika końcowego na podstawie tych właśnie elementów języka.
Wstęp: Komunikaty o błędach.
W języku C i C++ stałe mogły być definiowane na wiele sposobów. Mogliśmy wykorzystać modyfikator const, aby oznaczyć zmienną jako “niezmienną” [co oczywiście dało się na wiele sposobów obejść - jak to w C ;]], lub uruchomić mechanizm preprocesora i zdefiniować potrzebne nam stałe za pomocą makra #define. W języku PHP także mamy kilka możliwości definiowania stałych. Są to:- funkcja define(), tworząca globalnie rozpoznawalny identyfikator wartości [odpowiednik #define],
- słowo kluczowe const, pozwalające na stworzenie publicznej stałej w ramach klasy [w pewnym sensie odpowiednik modyfikatora const z C].
define('WARNING', 0xF0);
define('FATAL_ERROR', 0xFF);
// ...
if($value < 0)
{
echo 'Error: '.FATAL_ERROR.' in '.__FILE__.':'.__LINE__;
}
// Error: 255 in index.php:32
Na górze znajdują się definicje stałych oznaczających kody poszczególnych błędów, a następnie przykładowy kod “wyrzucający” błąd na ekran. Ostatnia linijka zawiera potencjalny wygląd takiego błędu w wyniku działania powyższego skryptu. Każdy programista z większym doświadczeniem zada sobie od razu pytanie - a co, jeśli będzie więcej rodzajów błędów? Czy będę musiał pamiętać nazwy wszystkich stałych? Oczywiście nie, ponieważ można to wykonać w nieco lepszy sposób, np.:
class Errors
{
const WARNING = 0xF0;
const FATAL = 0xFF;
}
// ...
if($value < 0)
{
echo 'Error: '.Errors::FATAL.' in '.__FILE__.':'.__LINE__;
}
// Error: 255 in index.php:32
W tym momencie przechowujemy listę kodów błędów w jednym miejscu, a więc mamy nad nimi o wiele większą kontrolę. Możemy też użyć klasy Errors jako referencji dla istniejących rodzajów błędów tak, aby każdy programista w zespole był świadomy tego, co potencjalnie go czeka. Nadal jednak nie zmienił się sposób wyświetlania komunikatu dla użytkownika końcowego. Czy można coś z tym zrobić?
PHP: Lista stałych zdefiniowanych w klasie.
Oczywiście, że można! ;] Załóżmy, że będziemy przechowywać flagi jako stałe zawarte w odpowiedniej klasie. Załóżmy ponadto, że nazwy naszych flag będą nieco bardziej informatywne, niż podane wyżej. ;] Poniższy listing definiuje listę kodów komunikatów:class Messages
{
const NOT_ENOUGH_PRIVILEGES = 0x00;
const FAILED_TO_OPEN_CONNECTION = 0x01;
const UNCAUGHT_EXCEPTION = 0x02;
// ...
const UNKNOWN_ERROR = 0xFF;
}
W tym momencie następuje “magia”. Otóż, korzystając z opisywanej przeze mnie wcześniej refleksji w języku PHP możemy odczytać także listę stałych zdefiniowanych w danej klasie. Odbywa się to w następujący sposób:
$r = new ReflectionClass('Messages');
$constants = $r->getConstants();
var_dump($constants);
Wynik:
array(4) {
["NOT_ENOUGH_PRIVILEGES"]=>
int(0)
["FAILED_TO_OPEN_CONNECTION"]=>
int(1)
["UNCAUGHT_EXCEPTION"]=>
int(2)
["UNKNOWN_ERROR"]=>
int(255)
}
Prawda, że proste? Ze względu na fakt, że będziemy chcieli się odwołać do numerów komunikatów, zamiast ich nazw, skorzystamy jeszcze z dobrodziejstwa funkcji array_flip(), która zamienia klucze tablicy z jej wartościami. Możemy teraz zmienić nieco kod z przykładu z klasami, otrzymując finalnie następujący listing:
class Messages
{
const NOT_ENOUGH_PRIVILEGES = 0x00;
const FAILED_TO_OPEN_CONNECTION = 0x01;
const UNCAUGHT_EXCEPTION = 0x02;
// ...
const UNKNOWN_ERROR = 0xFF;
}
// ...
$r = new ReflectionClass('Messages');
$constants = array_flip($r->getConstants());
// ...
if($value < 0)
{
echo 'Error: '.$constants[Messages::NOT_ENOUGH_PRIVILEGES].' in '.__FILE__.':'.__LINE__;
}
// Error: NOT_ENOUGH_PRIVILEGES in index.php:32
Oczywiście do niniejszego błędu można jeszcze dodać jakiś własny komentarz, aczkolwiek to pozostawiam już Waszej inwencji. Myślę, że pokazane dzisiaj informacje przyczynią się do zwiększenia Waszych możliwości korzystania z mechanizmów języków interpretowanych i wyciśnięcia z nich “ostatnich soków” [a jest co wyciskać ;]]. Do zobaczenia w kolejnym wpisie!