我们在写项目过程中,为了数据的安全,系统会去做数据的验证工作。
但是我们在开发的过程中,数据验证的方法去写,又是一件很麻烦的事情,那能不能实现为自动验证呢?
怎么实现自动验证? 我想把函数传递过来的变量,按照规则进行 匹对。如果有问题就直接 抛出错误。
其实 实现 的原理很简单, 通过一个代理类,__call 去调用方法,这个代理类中不存放其他的方法,就会自动去调用__call 这个方法
return call_user_func_array([$this->_instance, $method], $args);
我们现在来看看代码是如何运行,运转的
建立一个控制器
UserController.php
/**
* 更新用户信息
* @param string $username <POST> 用户名
* @param string $password <POST> 密码
* @return array
*/
public function update(){
$username=$this->_post('username');
$password=$this->_post('password');
$result=$this->User_model->update(['id'=>23],$username,$password);
return $result;
}好的,我们在这里没有看到一点的验证,那么说 username、password不能为空 如何验证?
password长度不能小于6位 如何处理?
User_model.php
/**
* 用户更新
* @param string $username <required> 用户名
* @param string $password <required> 密码
* @param array $where
* @return true|false 返回添加结果
*/
public function update($where,$username,$password){
//进行更新操作
%result=$this->db->update('manage_platform', $role_data, ['manage_id' => $id, 'platform_id' => $role_data['platform_id']]);
returen $result;
}好的,可以看出方法上面的验证规则,$username 是一个string类型,且required类型。
那么如何就自动验证了呢?看看 $this->User_model 这是如何来的?
final public function __get($name) {
static $lazy;
if (is_null($lazy)) {
if (is_file($file = APPPATH . 'config/lazy_init.php')) require $file;
else $lazy = [];
}
if (isset($lazy[$name]) && is_callable($lazy[$name])) $value = $lazy[$name]();
elseif (class_exists($name, TRUE)) {
$value = new Model_Proxy(new $name()); //看到这句话就知道怎么回事了 其实获取到的是一个代理类
}
else throw new InvalidArgumentException('Undefined property: ' . get_called_class() . '::$' . $name);
$this->$name = $value;
return $value;
}//获取到的是一个代理类:
$result=$this->User_model
Model_Proxy.php
<?php
defined('APPPATH') or die('Access restricted!');
class qb_Model_Proxy {
private $_rules = NULL;
private $_class = NULL; //类名
private $_instance = NULL; //实例
const IGNORE = ['Base_model', 'qb_Model', 'CI_Model'];
public function __construct($instance) {
$this->_class = get_class($instance);
$this->_instance = $instance;
LoadClass('helperReflection') || showException('helperReflection not found.');
}
final public function __get($name) {
if (isset($this->_instance->$name)) return $this->_instance->$name;
else throw new InvalidArgumentException('Undefined property: ' . $this->_class . '::$' . $name);
}
final public function __set($name, $value) {
$this->_instance->$name = $value;
}
//等于所有的方法 都会经过__call 这个方法,先进行 checkForm 进行验证,如果没有通过,返回错误信息,如果已经通过
//执行 call_user_func_array(); 这个方法
final public function __call($method, array $args) {
if ($method[0] !== '_' && method_exists($this->_instance, $method)) {
ENVIRONMENT === 'development' && debugLog('自动验证 ' . $this->_class . '->' . $method . jsonencode($args));
isset($this->_rules) || $this->_rules = $this->_makeRules();
if (isset($this->_rules['rules'][$method], $this->_rules['params'][$method])) {
try {
checkForm($this->_rules['rules'][$method]
, $this->_combineParam($this->_rules['params'][$method], $args), NULL);
}
catch (Exception $e) {
showError($e->getMessage());
}
}
}
return call_user_func_array([$this->_instance, $method], $args);
}
/**
* 生成配置规则文件 (方法下同名规则将被覆盖)
* @return array|false
*/
private function _makeRules() {
if (in_array($this->_class, self::IGNORE)) return FALSE;
if (is_file($cache = FCPATH . 'data/ci/cache/form_' . $this->_class . '.php')) {
$config = require $cache;
if (is_file($config['file']) && filemtime($config['file']) < $config['time']) return $config;
}
$config['rules'] = [];
$config['params'] = [];
$ref = new helperReflection($this->_instance);
foreach ($ref->getAllComment('/^\s+\*\s@param\s+(\w+)\s+\$(\w+)\s+<([^>]+)>\s+([^\s ]+)/im'
, self::IGNORE) as $key => $item) {
for ($i = 0; $i < count($item[0]); $i++) {
$config['rules'][$key][] = [
'field' => $item[2][$i],
'label' => $item[4][$i],
'rules' => $item[3][$i],
];
}
$config['params'][$key] = $ref->getMethodParams($key, TRUE);
}
$config['time'] = time();
$config['file'] = $ref->getFileName();
file_put_contents($cache, '<?php' . PHP_EOL . PHP_EOL . 'return ' . var_export($config, TRUE) . ';');
return $config;
}
/**
* 暴力合并形参与实参 (实参最后值为数组时,附加上)
* @param array $params 函数形参
* @param array $values 调用实参
* @return array
*/
private function _combineParam(array $params, array $values) {
$i = 0;
$result = [];
foreach ($params as $key => $item) {
if (is_numeric($key)) { //无默认值
if (!array_key_exists($i, $values)) {
showException('Parameter declaration or configuration error.');
}
$key = $item;
$value = $values[$i];
}
else $value = array_key_exists($i, $values) ? $values[$i] : $item;
$i++;
$result[$key] = $value;
}
is_array($value = end($values)) && $result += $value;
return $result;
}
}https://www.cnblogs.com/loveyoume/p/6099966.html