Począwszy od wersji 5.3.0 dostaliśmy nową fajną funkcję do czarowania w PHP. Do tej pory jeżeli chcieliśmy wywoływać funkcję, która nie istnieje, musieliśmy używać __call
. Teraz dodano __callStatic
. Przyznam się, że jakoś mi umknęła. Jak sama nazwa mówi, służy do wywoływania nieistniejących metod statycznych. Pomyślałem, że warto wymyślić dla niej jakieś sensowne zadanie.
W ilu miejscach kodu sprawdzacie wielokrotnie zmienne czy nie są nulami, czy nie są puste, a jak spełnią te dwa warunki, to czy są liczbami całkowitymi i czy nie są większe niż np. 5? Sprawdzenie tych wszystkich warunków powoduje masę IFów. Nie lepiej byłoby sprawdzać tak
if (Walidator::check_notNull_notEmpty_isInt_gt5($zmienna)) {
// poprawna wartosc
}
Fajne, co? Bez tworzenia obiektów, złożonych funkcji warunkowych itp. Dla setterów jak znalazł Kolejne elementy nazwy zawężają warunek poprawności.
Klasa powstała w ok. 1 godz., dlatego używajcie na własną odpowiedzialność. W ciągu kilku dni wrzucę klasę na githuba i trochę potestuję w kierunku błędów, dorzucę kilka interesujących warunków itp. Może się komuś przyda.
<?php
class Walidator {
/**
* Reaguje na funkcje rozpoczynajace sie od 'check_'.
* Jako separatora uzywac znaku _
* @param string $name nazwa nieisniejacej funkcji
* @param array $args podane parametry
* @return bool
*/
public static function __callStatic($name, $args) {
if (stripos($name, 'check_') === 0) {
// obcinamy poczatek
$name = substr($name, 6);
// rozdzielamy skladowe nazwy
$extractedNames = explode('_', $name);
// przelatujemy po wszystkich rozdzielonych funkcjach
foreach($extractedNames as $funcName) {
// rozpracowujemy nazwe funkcji
$funcName = self::extractFunction($funcName);
// sprawdzamy czy rozpracowana funkcja istnieje
if (!method_exists(__CLASS__, $funcName['funkcja'])) {
throw new Exception("Funkcja {$funcName} nie istnieje!");
}
// sprawdzamy czy w parametrze podano
// tablice z wartosciami do sprawdzenia
if (is_array($args[0])) {
foreach ($args[0] as $arg) {
// gwozdz programu! wywolujemy
// rozpracowana funkcje i podajemy ewentualne
// dodatkowe parametry
if (self::$funcName['funkcja']($arg, $funcName['args']) == false) {
return false;
}
}
}
// jezeli parametr nie jest tablica
else {
if (self::$funcName['funkcja']($args[0], $funcName['args']) == false) {
return false;
}
}
}
// jezeli dolecialo az tutaj tzn., ze wartosc poprawnie zwalidowana
return true;
}
// wylapie zle skonstruowany poczatek nazwy funkcji
throw new Exception("Próba wywołania nierozpoznanej funkcji {$name}");
}
/**
* Szuka znanych sobie funkcji skladowych do wywolania.
* @param string $name
* @return array tablica z nazwa funkcji i parametrami
*/
protected static function extractFunction($name) {
// calosc na male litery
$name = strtolower($name);
// jezeli zaczyna sie od 'not'
if (stripos($name, 'not') === 0) {
// ciachnij 'not'
$name = substr($name, 3);
// to co zostalo napisz z duzej litery
$name = 'not' . ucfirst($name);
return array(
'funkcja' => $name,
'args' => null);
}
// to samo jezeli zaczyna sie od 'is'
elseif (stripos($name, 'is') === 0) {
$name = substr($name, 2);
$name = 'is' . ucfirst($name);
return array(
'funkcja' => $name,
'args' => null);
}
elseif (stripos($name, 'gt') === 0) {
return array(
'funkcja' => 'gt',
// to co zostalo musi byc parametrem gt
'args' => substr($name, 2));
}
elseif (stripos($name, 'eq') === 0) {
return array(
'funkcja' => 'eq',
'args' => substr($name, 2));
}
elseif (stripos($name, 'between') === 0) {
$name = substr($name, 7);
return array(
'funkcja' => 'between',
// z tego co zostalo
// rozwalamy wartosci przy 'and'
'args' => explode('and', $name));
}
elseif (stripos($name, 'maxlength') === 0) {
return array(
'funkcja' => 'maxLength',
'args' => substr($name, 9));
}
// jezeli doszlo az tutaj to
// nierozpoznano funkcji i
// wywalam wyjatek
else {
throw new Exception("Nie rozpoznano funkcji {$name}");
}
}
Skoro mamy szkielet do rozpoznawania funkcji to wrzucimy sobie trochę funkcji walidujących.
public static function isNull($var) {
return is_null($var);
}
public static function notNull($var) {
return !is_null($var);
}
public static function isEmpty($var) {
return empty($var);
}
public static function notEmpty($var) {
return !empty($var);
}
public static function isInt($var) {
return is_int($var);
}
public static function isString($var) {
return is_string($var);
}
/**
* Sprawdza czy $var jest wieksze lub rowne $arg.
* @param numeric $var
* @param numeric $arg
* @return bool
*/
public static function gt($var, $arg) {
if (!is_numeric($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest liczba!");
if (!is_numeric($arg)) throw new Exception("Warunek {$arg} nie jest liczba!");
return ($var > $arg);
}
/**
* Sprawdza czy $var jest rowne $arg.
* @param numeric $var
* @param numeric $arg
* @return bool
*/
public static function eq($var, $arg) {
if (!is_numeric($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest liczba!");
if (!is_numeric($arg)) throw new Exception("Warunek {$arg} nie jest liczba!");
return ($var == $arg);
}
/**
* Sprawdza czy $var znajduje sie w przedziale $arg[0] <= $var <= arg[1].
* @param numeric $var
* @param array $arg $arg[0] i $arg[1] typu numeric
* @return bool
*/
public static function between($var, array $arg) {
if (!is_numeric($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest liczba!");
if (!is_numeric($arg[0]) || !is_numeric($arg[1])) throw new Exception("Warunek {$arg[0]} lub {$arg[1]} nie jest liczba!");
return (($var >= $arg[0]) && ($var <= $arg[1]));
}
/**
* Sprawdza max dlugosc ciagu $var.
* @param string $var
* @param int $arg
* @return bool
*/
public static function maxLength($var, $arg) {
if (!is_string($var)) throw new Exception("Sprawdzana wartosc {$var} nie jest stringiem!");
if (!is_numeric($arg)) throw new Exception("Warunek {$arg} nie jest liczba calkowita!");
return (strlen($var) <= (int) $arg);
}
Skoro mamy „klocki”, z których możemy budować sobie warunki walidacji, poniżej kilka testów
if (Walidator::check_notempty_isint_gt5_between1and9($test)) {
echo 'wartosc poprawna';
}
else {
echo 'BLAD!';
}
Dla wartości 6.5
funkcja zwróci błąd (isInt
), dla tablicy array(6,7,8,9)
wartość poprawną, z kolei Walidator::check_maxLength4(array('ala','miala','kota'))
zwróci również błąd, bo ‚miala’ ma 5 znaków