欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

详解thinkphp的I函数源码及运转流程和用法

程序员文章站 2022-05-03 10:24:59
...

上次写了U函数,今天就把I函数的源码解读和流程图记录下来,作为分享,顺便会对使用稍微做一些解释。


一 、函数使用方法:


参数1:$name 

这个传递的是要过滤的变量名,里面可以包含数据来源方式method和数据类型type  格式为 method.name/type 例如 post.pram/s

method的方式非常多,具体最好参看源码,这里不具体说了。

要注意这里规定过滤数据的type后,会使用对应的强制转换,例如type为int,则用(int)方式进行转换。如果规定的type在I函数内不存在,则默认强制转换成字符串

type对应  a为数组    b为布尔    d为整形数     f为浮点数


参数2:$default

这个传递的是默认值,如果过滤后的变量不存在,则返回该默认值


参数3:$filter 默认为null

这个传递的是过滤的多个函数或者filter_id以及正则表达式


一个或多个函数:字符串格式多个函数用,隔开,还可以用数组方式,多个函数会循环进行过滤,且过滤的数据可以是多维数组,因为可以递归过滤,另外因为多个函数是循环进行过滤,所以过滤的顺序也是按照循环的顺序进行,所以要注意多个过滤函数的顺序放置。


正则表达式: /表达式/ 正则表达式的过滤方式不能进行递归,所以过滤的数据不能是数组


filter_id形式:整型的int类型或者数组类型都可以,最后用filter_var根据filter_id对应的过滤方式进行过滤,该种方式也是不进行递归的,所以过滤的数据不能是数组


参数4:$datas 默认为null

这个传递参数用来补充method中的data方式,是传递获取额外数据源的数据给过滤变量的


二、I函数运行流程图


详解thinkphp的I函数源码及运转流程和用法



三、I函数源码解读:


/**
 * 获取输入参数 支持过滤和默认值
 * 使用方法:
 * <code>
 * I('id',0); 获取id参数 自动判断get或者post
 * I('post.name','','htmlspecialchars'); 获取$_POST['name']
 * I('get.'); 获取$_GET
 * </code>
 * @param string $name 变量的名称 支持指定类型和method
 *                     格式 get.cc/d get为method cc为变量名称 d为指定数据类型
 * @param mixed $default 不存在的时候默认值
 * @param mixed $filter 参数过滤方法 可以是函数名,也可以是int类型指定filter_var里的过滤id
 * @param mixed $datas 要获取的额外数据源
 * @return mixed
 */
function I($name,$default='',$filter=null,$datas=null) {
    /*建立静态变量$_PUT赋值为null*/
	static $_PUT	=	null;
    /*检查变量名称$name里面是否存在/*/
	if(strpos($name,'/')){ // 指定修饰符
        /*如果存在且/不是首字符,则根据其/分割为两个单元的数组,并用list分别赋值给$name以及$type
        $name是变量名称,$type是变量模式,有强制转化为字符串模式s*/
		list($name,$type) 	=	explode('/',$name,2);

    /*检测配置VAR_AUTO_STRING(强制将变量转化为字符串,如果需要变量本身,则必须加变量修饰符$)是否开启*/
	}elseif(C('VAR_AUTO_STRING')){ // 默认强制转换为字符串
        /*如果开启了,则将$type赋值为s,也就是字符串模式 ???*/
        $type   =   's';
    }



    /*检测$name变量名中是否含有.*/
    if(strpos($name,'.')) { // 指定参数来源
        /*如果有且不在首字符,则根据.分割成两个单元的数组,并用list分别将其赋值给$method以及$name
        $method为 $name为*/
        list($method,$name) =   explode('.',$name,2);

    /*如果不存在.*/
    }else{ // 默认为自动判断
        /*则将param赋值给$method*/
        $method =   'param';
    }


    /*将$method转变为小写,并进行相应的判断*/
    switch(strtolower($method)) {
        /*如果是get*/
        case 'get'     :   
            /*则引用$_GET并赋值给$input*/
        	$input =& $_GET;
        	break;
        /*如果是post*/
        case 'post'    :   
            /*引用$_POST并赋值给$input*/
        	$input =& $_POST;
        	break;
        /*如果是put*/
        case 'put'     :   
            /*检查$_PUT是否为null*/
        	if(is_null($_PUT)){
                /*如果是则获取php://input的内容并赋值给$_PUT php://input无法读取enctype=multipart/form-data的数据,会为空*/
            	parse_str(file_get_contents('php://input'), $_PUT);
        	}
            /*将$_PUT的值赋值给$input*/
        	$input 	=	$_PUT;        
        	break;
        /*如果是param则自动判断是哪种类型*/
        case 'param'   :
            /*检查$_SERVER的请求方式*/
            switch($_SERVER['REQUEST_METHOD']) {
                /*如果是POST类型*/
                case 'POST':
                    $input  =  $_POST;
                    break;
                /*如果是PUT类型*/
                case 'PUT':
                	if(is_null($_PUT)){
                    	parse_str(file_get_contents('php://input'), $_PUT);
                	}
                	$input 	=	$_PUT;
                    break;
                /*不是以上两种则为GET类型*/
                default:
                    $input  =  $_GET;
            }
            break;
        
        /*如果是path类型*/
        case 'path'    :  
            /*设定$input为空数组*/ 
            $input  =   array();
            /*检查$_SERVER的path_info值是否为空*/
            if(!empty($_SERVER['PATH_INFO'])){
                /*不为空,则将url分隔符的配置赋值给$depr*/
                $depr   =   C('URL_PATHINFO_DEPR');
                /*去除$_SERVER['PATH_INFO']两端的url分隔符$depr,然后再根据$depr分割成数组赋值给$ipnut*/
                $input  =   explode($depr,trim($_SERVER['PATH_INFO'],$depr));            
            }
            break;

        /*如果是request类型*/
        case 'request' : 
            /*引用$_REQUEST的值赋值给$input*/  
        	$input =& $_REQUEST;   
        	break;

        /*如果是session类型*/
        case 'session' :   
            /*引用$_SESSION的值赋值给$input*/
        	$input =& $_SESSION;   
        	break;

        /*如果是cookie类型*/
        case 'cookie'  :   
            /*引用$_COOKIE类型赋值给$input*/
        	$input =& $_COOKIE;    
        	break;

        /*如果是server类型*/
        case 'server'  :   
            /*引用$_SERVER赋值给$input*/
        	$input =& $_SERVER;    
        	break;

        /*如果是globals类型*/
        case 'globals' :   
            /*引用$_GLOBALS赋值给$input*/
        	$input =& $GLOBALS;    
        	break;

        /*如果是data类型,则直接调用用户传入的数据源$datas*/
        case 'data'    :   
            /*引用$datas赋值给$input*/
        	$input =& $datas;      
        	break;

        /*如果不属于以上任何类型*/
        default:
            /*则返回null*/
            return null;
    }

    /*检测$name是否为空,$name是要读取的变量名*/
    if(''==$name) { // 获取全部变量
        /*如果为空将上面的$input赋值给$data*/
        $data       =   $input;

        /*检测用户是否设置$filter参数过滤方法,有则返回给$filters,
        没有则将默认的过滤配置DEFAULT_FILTER的值返回给$filters*/
        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');

        /*检测$filters是否存在*/
        if($filters) {
            /*如果存在,检查$filters是否为字符串格式*/
            if(is_string($filters)){
                /*如果是字符串,则用,分割$filters成数组重新赋值给$filters*/
                $filters    =   explode(',',$filters);
            }

            /*循环$filters,将循环的值赋值给$filter*/
            foreach($filters as $filter){
                /*循环的每个$filter作为函数处理$data后返回给$data*/
                $data   =   array_map_recursive($filter,$data); // 参数过滤
            }
        }

    /*检查$input[$name]是否设置了*/
    }elseif(isset($input[$name])) { // 取值操作
        /*如果设置了,则将$input[$name]赋值给$data*/
        $data       =   $input[$name];
        /*检查用户是否设置$filter,设置了则赋值给$filters,否则用默认的过滤配置赋值给$fitlers*/
        $filters    =   isset($filter)?$filter:C('DEFAULT_FILTER');
        /*检查$filters是否存在*/
        if($filters) {
            /*检查$filters是否为字符串*/
            if(is_string($filters)){
                /*如果是字符串,则检查$filters首字符是否为/*/
                if(0 === strpos($filters,'/')){
                    /*如果首字符为/则认定为过滤方法是正则匹配的方式,所以将$data强制转换成字符串,
                    然后将$filters作为正则匹配的表达式,用preg_match进行匹配,并检测匹配结果*/
                    if(1 !== preg_match($filters,(string)$data)){
                        // 支持正则验证
                        /*如果不匹配,则返回用户提交的$default值,如果用户没有设定$default,则返回null*/
                        return   isset($default) ? $default : null;
                    }
                /*如果$filters首字符不是/*/
                }else{
                    /*则根据,分割$filters并重新赋值给自身*/
                    $filters    =   explode(',',$filters);                    
                }
            /*如果$filters不为字符串,则检测是否为int类型*/
            }elseif(is_int($filters)){
                /*如果是int类型,则将$filters强制转变为数组并赋值给$filters*/
                $filters    =   array($filters);
            }
            
            /*检查$filters是否为数组*/
            if(is_array($filters)){
                /*将$filters循环,每次循环的值赋值给$filter*/
                foreach($filters as $filter){
                    /*检查循环出来的$filter函数是否存在*/
                    if(function_exists($filter)) {
                        /*如果存在,则检测$data是否是数组,如果是则用array_map_recursivve递归执行$filter函数处理$data
                        如果不是数组,则直接用$filter作为函数处理$data,最后将执行结果赋值给$data*/
                        $data   =   is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤
                    /*如果$filter函数不存在*/
                    }else{
                        /*检查$filter是否是int类型,如果是,则返回$filter,如果不是,则用filter_id获取其对应的id返回
                        将返回值,作为filter_var的第二次参数过滤选型对$data进行过滤,处理完后返回赋值给$data*/
                        $data   =   filter_var($data,is_int($filter) ? $filter : filter_id($filter));

                        /*检查$data是否为false*/
                        if(false === $data) {
                            /*检查用户提交的$default是否设置,如果设置则返回$default,如果没有设置则返回null*/
                            return   isset($default) ? $default : null;
                        }
                    }
                }
            }
        }

        /*如果$type不为空*/
        if(!empty($type)){
            /*根据转为小写后的$type类型来强制转换$data的类型*/
        	switch(strtolower($type)){
        		case 'a':	// 数组
        			$data 	=	(array)$data;
        			break;
        		case 'd':	// 数字
        			$data 	=	(int)$data;
        			break;
        		case 'f':	// 浮点
        			$data 	=	(float)$data;
        			break;
        		case 'b':	// 布尔
        			$data 	=	(boolean)$data;
        			break;
                case 's':   // 字符串
                /*如果以上都不符合*/
                default:
                    /*则将$data强制转换成字符串类型*/
                    $data   =   (string)$data;
        	}
        }

    /*如果$name不为空值,同时不存在$input[$name]*/
    }else{ // 变量默认值
        /*则检查用户提交的$default默认值是否设置,如果设置了返回其作为$data,如果没有设置,则返回null作为$data*/
        $data       =    isset($default)?$default:null;
    }

    /*检查$data为数组的话,则使用array_walk_recursive处理$data递归使用执行think_filter函数,
    think_filter猜测是对数据查询进行特别过滤,匹配查询语句的都在后方添加了一个空格,这里我自己
    也没太懂*/
    is_array($data) && array_walk_recursive($data,'think_filter');

    /*返回$data*/
    return $data;
}