我们在写项目过程中,为了数据的安全,系统会去做数据的验证工作。
但是我们在开发的过程中,数据验证的方法去写,又是一件很麻烦的事情,那能不能实现为自动验证呢?
怎么实现自动验证? 我想把函数传递过来的变量,按照规则进行 匹对。如果有问题就直接 抛出错误。
其实 实现 的原理很简单, 通过一个代理类,__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