Thinkphp框架感悟(二)
这次主要分析一下I方法
/** * 获取输入参数 支持过滤和默认值 * 使用方法: * <code> * I('id',0); 获取id参数 自动判断get或者post * I('post.name','','htmlspecialchars'); 获取$_POST['name'] * I('get.'); 获取$_GET * </code> * @param string $name 变量的名称 支持指定类型 * @param mixed $default 不存在的时候默认值 * @param mixed $filter 参数过滤方法 * @param mixed $datas 要获取的额外数据源 * @return mixed * */ function I($name,$default='',$filter=null,$datas=null) { static $_PUT = null; /** * 这个if存在的意义是:I方法有一种写法为I('变量类型.变量名/修饰符');,这种写法可以通过修饰符的不同,将得到的变量强制转换为各个不同的类型 * 于是就需要一个if来判断是否为带“/”的写法。 * strpos()可以查出参数里第一个/的位置, * * 如果查到了“/”,则用explode将$name字符串拆成两个字符串. * explode()的作用是将$name转换为一维数组,以"/"为标记拆分, * 如:$demo = "abcd/12345"; var_dump(explode('/',$demo,2)); * 得到的结果为 array (size=2) * 0 => string 'abcd' (length=4) * 1 => string '12345' (length=5) * * 再通过list函数,将“/”前的字符串赋值给$name,将"/"后面的字符串赋值给$type * * 结果:$name为“变量类型.变量名” * $type为“修饰符” * * 如果参数传入时的格式不是I('变量类型.变量名/修饰符')这种, * 则查看是否设置“配置参数'VAR_AUTO_STRING'”,该参数的作用是默认强制转换为字符串 $type = 's'; */ if(strpos($name,'/')){ list($name,$type) = explode('/',$name,2); }elseif(C('VAR_AUTO_STRING')){ $type = 's'; } /** *这个if的运行过程与上一个if一样,判断传入的参数$name(也可以是经过上面步骤处理过的$name)。 * 最后变量类型(param、get、post等)被赋值给了$method。变量名被赋值给了$name * * 如果写的格式为I('变量名'),即没写“.”和变量类型, * 则默认变量类型为param */ if(strpos($name,'.')) { list($method,$name) = explode('.',$name,2); }else{ $method = 'param'; } /** * strtolower()函数的作用是将字符全部转化为小写 * 通过$method1的不同,对$input赋不同的传输类型(注:此处的&不是很明白, &的用法是让两个变量指向同一个内容,不知去掉&会怎么样) */ switch(strtolower($method)) { case 'get' : $input =& $_GET; break; case 'post' : $input =& $_POST; break; case 'put' : if(is_null($_PUT)){ parse_str(file_get_contents('php://input'), $_PUT); } $input = $_PUT; break; /** * 此处的$_SERVER是获取系统变量的方法, * $_SERVER['REQUEST_METHOD'] 是查看访问页面时的请求方法。例如:“GET”、“HEAD”,“POST”,“PUT”。 * 从而达到“自动判断请求类型”的目的 * (所以,无论html页面传过来数据用的传输方法是get还是post,都能用param来接收) */ case 'param' : switch($_SERVER['REQUEST_METHOD']) { case 'POST': $input = $_POST; break; case 'PUT': if(is_null($_PUT)){ parse_str(file_get_contents('php://input'), $_PUT); } $input = $_PUT; break; default: $input = $_GET; } break; /** * 下面依旧是通过$method1的不同,对$input赋不同的“关键变量名”,用以获取各种系统变量。 */ case 'path' : $input = array(); if(!empty($_SERVER['PATH_INFO'])){ $depr = C('URL_PATHINFO_DEPR'); $input = explode($depr,trim($_SERVER['PATH_INFO'],$depr)); } break; case 'request' : $input =& $_REQUEST; break; case 'session' : $input =& $_SESSION; break; case 'cookie' : $input =& $_COOKIE; break; case 'server' : $input =& $_SERVER; break; case 'globals' : $input =& $GLOBALS; break; case 'data' : $input =& $datas; break; default: return null; } /** * 此时$name的内容为变量名,而$input为$_post之类的接收类型变量 * * 如果变量名$name为空,则意味着无变量名传入,传入的只是一个接收类型变量 * 那么这个接收类型变量里其实是所有的用该类型传输过来的内容(如只有$_POST则是一个数组,里面是各种来自method="post" 的表单中的值) * 所以不写变量名代表不是接收特定的键值名传过来的内容,而是接收所有通过“该方法”传过来的内容,并存进“传输类型变量”这个数组里 * 所以,如果变量名$name为空,我们将整个接收到的数组赋值给$data, * 其中isset函数的作用是检测变量是否存在:若变量不存在返回false,若其存在但值为null也返回false,只有存在且值不为null时才返回true * 这个$filter是I方法的第二个传入参数,为“参数过滤方法”(一般我都没传过这个参数),所以当我们传入“参数过滤方法”时,会按我们传入的方法过滤 * * 如果传入的$name不为空 * 则通过isset函数判断传过来的所有数据(是个二维数组,存放在$input($_POST之类)里面)里是否有键值名为$name的键值对 * 如果有,则将数据复制给$data,之后依然判断下是否传入了“参数过滤方法”,如果传入则过滤。 */ if(''==$name) { // 获取全部变量 $data = $input; $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); if($filters) { if(is_string($filters)){ $filters = explode(',',$filters); } foreach($filters as $filter){ $data = array_map_recursive($filter,$data); // 参数过滤 } } }elseif(isset($input[$name])) { // 取值操作 $data = $input[$name]; $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); if($filters) { if(is_string($filters)){ if(0 === strpos($filters,'/')){ if(1 !== preg_match($filters,(string)$data)){ // 支持正则验证 return isset($default) ? $default : null; } }else{ $filters = explode(',',$filters); } }elseif(is_int($filters)){ $filters = array($filters); } if(is_array($filters)){ foreach($filters as $filter){ if(function_exists($filter)) { $data = is_array($data) ? array_map_recursive($filter,$data) : $filter($data); // 参数过滤 }else{ $data = filter_var($data,is_int($filter) ? $filter : filter_id($filter)); if(false === $data) { return isset($default) ? $default : null; } } } } } /** * 所以现在$data里面其实装的是传输过来的具体内容。 * 之后再判断下是否有$type(修饰符,在前面有过详解),如果$type不为空,则依据$type,将$data转化成不同的类型 * 如果$type为空,则判定是否传入参数$default(当传输内容不存在时的默认值),如果有$default,则将其赋值给$data */ if(!empty($type)){ 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 = (string)$data; } } }else{ // 变量默认值 $data = isset($default)?$default:null; } /** * &&这个运算符的意思是:如果前面为假,那么后面的语句就不执行了。 * array_walk_recursive()函数的意思是:对数组中的每个元素应用用户自定义的函数(即:将数组$data放入函数think_filter中运算)(关于这个函数目前的用法我还不是很明确)。 * 最后先判断$data是否为数组, * 如果是数组,则运行array_walk_recursive函数(因为array_walk_recursive函数的第一个参数必须得是数组) */ is_array($data) && array_walk_recursive($data,'think_filter'); /** * 最后将$data输出 */ return $data; }