php开源一个mvc框架的诞生之Application类input方法

Posted OpenFramework

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php开源一个mvc框架的诞生之Application类input方法相关的知识,希望对你有一定的参考价值。

开篇说明过,我所实现的框架全局都由Application类接管。那么接下来将讲到对于一个动态网站很重要的功能-——‘数据接收’。


我所设计的不管是表单数据还是url传值乃至$_SERVER,$_COOKIE,$_ENV,php://input等都通过Applicaiton::input()进行获取。那么接下来将讲解下如何做到一个方法获取。并且还得注意一点也是非常重要的一点,数据过滤。这点对于安全来讲非常重要,那么我将通过自定义闭包函数以及内置方法来实现自定义过滤方法与默认过滤方法


回顾第一篇讲到的,框架启动通过Application::run()方法,执行Application::check()检测框架运行环境,如果是路由机制,调用linkphp\boot\Env::requestRouterHandle()方法,处理路由请求


具体class::Env类代码段


namespace linkphp\boot;
use linkphp\Application;

class Env
{

   static private $_instance;

   private $_request;

   private $_env;

   static public function getInstance()
   {
       if(!isset(self::$_instance)){
           self::$_instance = new self();
       }
       return self::$_instance;
   }

   //操作相应模式
   public function selectEnvModel($_env_object)
   {
       $this->_env = Application::get('envmodel');
       $this->_request = Application::get('request')
->
request();
       return $this;
   }

   public function requestRouterHandle()
   {
       $this->_request->setQueryParam();
       $this->_env->initialize();
       return $this;
   }

   public function requestCmdHandle()
   {
       $this->_request->setCmdParam(
Application::
input('server.argv'));
       $this->_env->initialize();
       return $this;
   }

}


进入Env::requestRouterHandle()方法,首先设置请求参数,进入linkphp\boot\http\HttpRequest::serQueryParam()方法


namespace linkphp\boot\http;

class HttpRequest
{

   private $cmd;

   private $cmd_param = [];

   private $cookie;

   private $env;

   private $server;

   private $_response;

   private $_input;

   private $queryParam = [];

   //请求方法
   private $request_method;

   //数据
   private $data;

   private $request_http_accept = 'json';

   public function __construct(ResponseDriver $response,

Input $input)
   {
       $this->_response = $response;
       $this->_input = $input;
   }

   public function setData($data)
   {
       $this->data = $data;
       $this->_response->setRequest($this);
       return $this;
   }

   public function setRequestMethod($method)
   {
       $this->request_method = $method;
       $this->_response->setRequest($this);
       return $this;
   }

   public function setRequestHttpAccept($accept)
   {
       $this->request_http_accept = $accept;
       $this->_response->setRequest($this);
       return $this;
   }

   public function getData()
   {
       return $this->data;
   }

   public function getRequestMethod()
   {
       return $this->request_method;
   }

   public function getRequestHttpAccept()
   {
       return $this->request_http_accept;
   }

   /**
    * 响应请求返回response 实例对象
    * @return Object[ResponseDriver] $this->_response
    */
   public function setResponse()
   {
       $this->_response->getDriver()->setResponse(
$this
->_response->getDriver()->output($this->data));

       return $this->_response->getDriver();
   }

   /**
    * 响应请求输出结果
    * @return $this->_request_http_accept
    */
   public function send()
   {
       $this->_response->getDriver()->setResponse(
$this
->_response->getDriver()->output($this->data))->send();
   }

   /**
    * 当前请求 HTTP_CONTENT_TYPE
    * @access public
    * @return string
    */
   public function contentType()
   {
       $contentType = $this->server('CONTENT_TYPE');
       if ($contentType) {
           if (strpos($contentType, ';')) {
               list($type) = explode(';', $contentType);
           } else {
               $type = $contentType;
           }
           return trim($type);
       }
       return '';
   }

   public function start()
   {
       return $this;
   }

   public function isMethod($method)
   {
       return $this->getRequestMethod() === $method;
   }

   public function isGet()
   {
       return $this->isMethod('get');
   }

   public function isPost()
   {
       return $this->isMethod('post');
   }

   public function isDelete()
   {
       return $this->isMethod('delete');
   }

   public function isPut()
   {
       return $this->isMethod('put');
   }

   public function isPatch()
   {
       return $this->isMethod('parch');
   }

   public function isHead()
   {
       return $this->isMethod('head');
   }

   public function isOptions()
   {
       return $this->isMethod('options');
   }

   public function setQueryParam()
   {
       $this->queryParam = array_merge($this->get(),

$this->post(),
$this
->file(),$this->server(),$this->cookie(),$this->env());
       return $this;
   }

   public function get($key='',$filter='')
   {
       return $this->_input->get($key,$filter);
   }

   public function post($key='',$filter='')
   {
       return $this->_input->post($key,$filter);
   }

   public function file($key='')
   {
       return $this->_input->file($key);
   }

   public function server($key='')
   {
       return $this->_input->server($key);
   }

   public function cookie($key='')
   {
       return $this->_input->cookie($key);
   }

   public function env($key='')
   {
       return $this->_input->env($key);
   }

   public function getInput($filter='')
   {
       return $this->_input->getInput($filter);
   }

   public function input($key = '',$filter)
   {
       if ($pos = strpos($key, '.')) {
           // 指定参数来源
           list($method, $key) = explode('.', $key, 2);
           if (in_array($method, ['get', 'post', 'file',
'server',
'cookie', 'env'])) {
               return $this->$method($key,$filter);
           }
       }
       return $key=='' ? $this->queryParam[$key] :
$this
->queryParam[$key];
   }

   public function setCmdParam($command)
   {
       if(is_array($command) && count($command)>1){
           $this->cmd = $command[1];
       }
   }

   public function cmd($key)
   {
       return $this->cmd_param[$key];
   }

}


设置请求参数方法


public function setQueryParam()
{
   $this->queryParam = array_merge($this->get(),$this->post(),
$this
->file(),
$this
->server(),$this->cookie(),$this->env());
   return $this;
}


将本次请求的所有get ,post,file,cookie,server,env等参数全部进行合并保存至$this->queryParam属性中。通过这个方法即将本次请求的相关参数全部存储,那么如何用到就是接下来要将的重点。


回到Application::input()input方法中


static public function input($param,$filter='')
{
   return self::httpRequest()->input($param,$filter);
}


最终调用的也是linkphp\boot\http\HttpRequest::input()方法接收两个参数一个键值一个过滤方法,上面也贴了代码段,回到上面看看具体实现了哪些功能


public function input($key = '',$filter)
{
   if ($pos = strpos($key, '.')) {
       // 指定参数来源
       list($method, $key) = explode('.', $key, 2);
       if (in_array($method, ['get', 'post', 'file',
'server', 'cookie', 'env'])) {
           return $this->$method($key,$filter);
       }
   }
   return $key=='' ? $this->queryParam : $this->queryParam[$key];
}


首先第一个参数可以通过input('test')或者具体调用get获取其他参数则通过,input('get.test')则只会从get请求的参数中获取


接下来我们以get请求参数获取为例,看看HttpRequest::get()方法做了哪些


public function get($key='',$filter='')
{
   return $this->_input->get($key,$filter);
}


框架初始化后就会通过构造方法将linkphp\boot\http\Input()类注入保存到$this->_input属性中那么最终调用的是linkphp\boot\http\Input::get()方法,看下执行代码段


public function get($key='',$filter)
{
   return $key=='' ? $this->param($_GET,$filter) :
$this->param($_GET[$key],$filter);
}


调用了Input::param()


public function param($data,$filters)
{
   $filter = $this->getFilter($filters);
   if (is_array($data)) {
       array_walk_recursive($data, [$this, 'filterValue'],

$filter);
       reset($data);
   } else {
       $this->filterValue($data,'',$filter);
   }
   return $data;
}


首先获取过滤方法调用Input::getFilter()方法,之后判断传入的传入的数据是否是数组,如果是数组通过array_walk_rocursive方法依次将数组中元素传入本类中filterValue方法中进行过滤


private function getFilter($filter)
{
   $filter = $filter ?: $this->filter();
   if (is_string($filter) && false === strpos($filter, '/'))
{
       $filter = explode(',', $filter);
   } else {
       $filter = (array) $filter;
   }
   return $filter;
}


public function filterValue(&$value,$key,$filters)
{
   foreach($filters as $filter){
       if($filter instanceof Closure){
           // 调用函数或者方法过滤
           $value = call_user_func($filter, $value);
       }
   }
   return $this->filterExp($value);
}


最终实现的自定义闭包过滤方法也是通过本类filterValue方法中进行实现,将传入的过滤参数判断是否为闭包函数如果是进行执行闭包,在这里是用引用参数传递保证

【php开源】一个mvc框架的诞生之Application类input方法


Happy New Year | 新年快乐


以上是关于php开源一个mvc框架的诞生之Application类input方法的主要内容,如果未能解决你的问题,请参考以下文章

php开源一个mvc框架的诞生之Application类input方法

原创Zend Framework 2框架之MVC

原创Zend Framework 2框架之MVC

ThinkPHP框架基础知识

为什么大部份开源项目不用MVC框架开发

在TP框架中,使用原生SQL有啥弊端