Wiadomo, mylić się jest rzeczą ludzką; tak więc jako pierwszą z biblioteki underscore “zbuduję” klasę przechwytywania wyjątków. Jako, że jednym z założeń jest jak najmniej klas, a klasy mają praktycznie istnieć samodzielnie, mogę się narazić wielu programistom tym co napiszę.
Narażenie będzie spowodowane dołączeniem obsługi loga i błędów w bibliotece.
Klasa rozszerzająca standardowe Exception. Z poprzedniego artykułu odnośnie ustawień mamy konfigurację:
class _E extends Exception
static private $_classSettings = array(
'errorSave' => 'file|screen', 'errorPath' => '',
'errorFiletemp'=> '{ -date-}{ -time-}.{ -session-}.error',
'logEnabled' => true, 'logSave' => 'file|screen',
'logPath' => '', 'logFiletemp' => '{ -time-}_{ -date-}_{ -session-}',
'logType' => 'debug', //info, log, debug(all)
'single' => false, 'output' => 'none', //file|screen
'exPath' => '', 'exFiletemp' => '{ -time-}_{ -date- }_{ -session- }'
);
Odpowiednio będą to:
Wartości klasy:
//logi i błędy
static private $_l = array();
static private $_e = array();
//błędy przekazane przez error handler
static private $_et = array (
E_ERROR => 'Error', E_WARNING => 'Warning', E_PARSE => 'Parsing Error',
E_NOTICE => 'Notice', E_CORE_ERROR => 'Core Error',
E_CORE_WARNING => 'Core Warning', E_COMPILE_ERROR => 'Compile Error',
E_COMPILE_WARNING => 'Compile Warning', E_USER_ERROR => 'User Error',
E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice',
E_STRICT => 'Runtime Notice',
E_RECOVERABLE_ERROR => 'Catchable Fatal Error'
);
Mamy przygotowane podstawy, teraz należy to oprogramować. Każde utworzenie instancji _E będzie równoznaczne z rzutowaniem wyjątku. Konstruktor klasy jest jedynym słusznym rozwiązaniem:
public function __construct($msg = null, $no = 0, Exception $exc = null)
{
parent::__construct($msg, $no, $exc);
// dane z wyjątku w czytelnej formie, dodajemy datę,
// info o pliku, linii, backtrace, co kto lubi
// tej metody nie pokazuje, każdy utworzy swoją własną
$_view = $this->_createView();
//zapisz wyjątek do logu błędów i zapisz/wyświetl całość
self::e('_E', 'Exception: '.$msg);
if (stripos(self::$_classSettings['output'], 'file')!==false) {
//zapis do pliku danych, metody nie muszę prezentować
$this->_file($_view);
}
if (stripos(self::$_classSettings['output'], 'screen')!==false) {
//wyświetlenie wyjątku
echo $_view;
}
}
// no i jakieś pobranie dodatkowe tych informacji
//
public function get()
{
return $this->_createView();
}
// a tutaj utworzenie widoku
//
private function _createView()
{
$_time = explode(" ", microtime());
$_time = $_time[0] + $_time[1];
$_head = sprintf(
"%s \t\t %s \n %s (%s) in file %s (%s)\n",
date('Y/m/d H:i:s'), $_time, $this->message,
$this->code, $this->file, $this->line
);
return $_head;
}
I to wszystko co do wyjątku. W konfiguracji klasy wybieramy czy wyjątek na ekran czy do pliku ma być skierowany. Pozostało jeszcze oprogramować logi i błędy.
//dodanie błędu: klasa z jakiej pochodzi, bład, typ błedu
static public function e($class, $error, $phperror='')
{
$phperror = ($phperror=='')?'Framework':$phperror;
list($_usec, $_sec) = explode(" ", microtime());
$_error = date("Y-m-d H:i:s")." ";
$_error .= sprintf('%2f', ($_usec + $_sec))."\t";
$_error .= str_pad($phperror, 15)."\t";
$_error .= str_pad($class." - ".$error, 100)."\n";
self::$_e[] = $_error;
}
//error handler
static public function err($errno, $errmsg, $filename, $linenum)
{
// jak kto woli - przekierowac blad
self::e(
$filename."[".$linenum."]", $errno." - ".$errmsg,
self::$_et[$errno]
);
// czy od razu rzutowac blad
throw new _E($errmsg, $errno);
}
// pobranie na ekran, do pliku albo zwrócenie jako wartość
// dowolność oprogramowania
//
static public function eGet($asValue=true)
{
}
static public function l($class, $text, $type='debug')
{
if (self::$_classSettings['logEnabled']==false) {
return;
}
$type = trim(strtolower($type));
//check log type
if ((self::$_classSettings['logType']!=='debug')
OR (self::$_classSettings['logType']!=='all')
) {
if ($type!==self::$_classSettings['logType']) {
return;
}
}
$_date = date("Y-m-d");
$_hour = date("H:i:s");
$_time = explode(" ", microtime());
$_time = $_time[0] + $_time[1];
self::$_l[] = array(
'type' => $type, 'time' => $_time, 'date' => $_date,
'hour' => $_hour, 'class' => $class, 'text' => $text
);
}
Rozwiązanie to ma kilka zalet (możliwe, że tylko ja je widzę). Po pierwsze, przechwytywanie wyjątków wykorzystywane będzie w każdej pozostałej klasie; oprócz tego dobrze by było dołączać logowanie błędów i zwykły log. Dzięki jednej klasie zmniejszam ilość wymaganych podpięć plików. Zmniejszona została zajętość zasobów poprzez wspólne wykorzystanie metod prywatnych do zapisu do pliku, formatowania, czy też przetwarzania nazwy pliku.
Utworzenie metod statycznych do logowania nie wymaga tworzenia obiektu, wystarczy wpisać _E::l lub _E::e by działało. Nazwy metod skrócone, by łatwiej je było zapamiętać. W kilku bibliotekach/frameworkach często się zastanawiałem, czy wpisywało się np addError czy też errorAdd. Zaznaczam, tworzę bibliotekę dla siebie, a nie dla Całego Świata. Dzielę się przemyśleniami, gdyż ktoś może je wykorzystać.
To jest projekt, szkic klasy. Niedługo po fazie testów będzie do pobrania paczka core klas biblioteki underscore. Zaznaczam, iż biblioteka jest połączeniem własnych rozwiązań z fragmentami rozwiązań podpatrzonymi we frameworkach Kohana i CodeIgniter, dodatkowo ostatnio odkryłem Fat-Free Framework i przeglądam jego składnię (może coś wykorzystam).
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.