作为程序员一定要保持良好的睡眠,才能好编程

项目中采用注释解析进行数据验证

发布时间:2018-08-01


我们在写项目过程中,为了数据的安全,系统会去做数据的验证工作。


但是我们在开发的过程中,数据验证的方法去写,又是一件很麻烦的事情,那能不能实现为自动验证呢?


怎么实现自动验证? 我想把函数传递过来的变量,按照规则进行 匹对。如果有问题就直接 抛出错误。




其实 实现 的原理很简单, 通过一个代理类,__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