📜 ⬆️ ⬇️

Typing and PHP

I don’t know about you, but it rarely happens to me that during debugging an application I’ve been poking around in the kernel and libraries for a long time, just to find out that the error was on the surface itself, say in the wrong parameter. And then you think “if it was not too lazy to add validation at the input of the function, I would save so much of my time!”. This is not difficult to do, but I do not want to spoil the transparency of business logic with a bunch of secondary conditions. In essence, this is a cross-cutting functionality and the AOP approach would be useful here, but officially PHP still does not support AOP. What to do? I now see the following solution.



// libs / Validate.php
final class Validate {
const Integer = 1;
const Title = 2;
const Variable = 3;
const TemplateFileName = 4;
const Boolean = 5;
const UserFileSection = 6;
const Gender = 7;
const Age = 8;
const Email = 9;

static function _checkStrLength($val, $strLen, $min=false, $max=false) {
if($min AND $strLen<$min) throw new Exception ("'{$val}' is less than {$min} characters long");
if($max AND $strLen>$max) throw new Exception ("'{$val}' is greater than {$max} characters long");
}

static function type($val, $type) {
switch ($type) {
case self::Integer:
if (strval(intval($val)) != $val) throw new Exception ("'{$val}' does not appear to be an integer");
break;
case self::Title:
self::_checkStrLength($val, UTF8::strlen($val), 1, 255);
break;
case self::Variable:
self::_checkStrLength($val, UTF8::strlen($val), false, 32);
if(!preg_match("/^[a-zA-Z][a-zA-Z0-9_]*$/is", $val)) throw new Exception ("'{$val}' contains invalid characters for a variable name");
break;
case self::TemplateFileName:
if(!file_exists(BASEDIR."/custom/views/xml/{$val}")) throw new Exception ("'{$val}' file not found");
break;
case self::Boolean:
if(!is_bool($val)) throw new Exception ("'{$val}' does not appear to be an boolean");
break;
case self::UserFileSection:
if($val!="avatar" AND $val!="file" AND $val!="marketplace" AND $val!="image" ) throw new Exception ("'{$val}' user file section is not valid");
break;
case self::Gender:
if($val!="male" AND $val!="female" AND $val!="undefined" ) throw new Exception ("'{$val}' gender is not valid");
break;
case self::Age:
if(($val<4 AND $val>99) OR $val==69 ) throw new Exception ("'{$val}' age is not valid");
break;
case self::Email:
if (!eregi("^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[az]{2,3})$", $val)) throw new Exception ("'{$val}' emaiol address is not valid");
break;
}
}
}


// Example.php
')
Class Page {
function add($parent_id, $title, $var, $template, array $permissions, $site_id, $activity_flag)
{
try {
Validate::type($parent_id, Validate::Integer);
Validate::type($site_id, Validate::Integer);
Validate::type($title, Validate::Title);
Validate::type($var, Validate::Variable );
Validate::type($template, Validate::TemplateFileName );
Validate::type($activity_flag, Validate::Boolean);
} catch (Exception $e) {
throw new Exception($e->getMessage());
return false;
}
}
//...
}

$p = new Page();

try {
$p->add(10,"Title", "var", "test.xml", array(), 1, 1);
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), "\n";
}


We start the class of the validator and define types for variables and their properties in it. Now, at the input of the function, it suffices to verify the passed parameters with the corresponding types.
For example:
try {
Validate::type($login, Validate::Variable);
Validate::type($real_name, Validate::Title);
Validate::type($real_email, Validate::Email);
Validate::type($real_gender, Validate::Gender);
Validate::type($real_age, Validate::Age);
} catch (Exception $e) {
throw new Exception($e->getMessage());
return false;
}

I do not pretend to a pattern with this decision, but perhaps it will be useful to someone.

Updated 09.28.08

Source: https://habr.com/ru/post/40935/


All Articles