然后现在回到 Router类中继续往下看:
if ($this->uri->uri_string == '') //假如此处为TRUE
{
if ($this->default_controller === FALSE)
{
上面的程序中以定义默认控制器为 home 所以此处肯定不执行错误提示
}
if (strpos($this->default_controller, '/') !== FALSE)
{
// 此处判断默认的控制器是否在子目录里面显然不是,跳过这个if,不过自己还是最好看看里面的程序
}
else
{
$this->set_class($this->default_controller); //给变量$class 赋值
$this->set_method('index'); //给变量 $method 赋值
//到这里为止控制器和方法已经被赋值了,但后面又有如下两个函数,我看了一下他们的作用,但是不知道写在这里的作用是什么,是为了给 数组 $segments 和 数组 $rsegments 赋值么,然后给其他函数用(又是哪个函数用了呢?),这里留个疑问,程序还没看完。
$this->_set_request(array($this->default_controller, 'index'));
}
这个函数_set_request他的作用就是给URI类下的 rsegments 数组赋值为 URL中被请求的类名和方法名
例如 URL为 index.php/home/index 则数组rsegments为 array('home','index')
$this->uri->_reindex_segments();//该函数的作用是给 URI类中 数组 $segments 和 数组 $rsegments 的开头插入一个NULL元素,但是不知道为什么要插入一个NULL,有什么作用啊?又是一个疑问
return; //然后返回,不再往下执行。
}
如果当uri_string != '' 时 ,执行下面的程序:四个函数 $this->uri->_remove_url_suffix(); //移除URL的后缀 即URL类中的 $this->uri_string 字串的后缀,当然这里我们的URL没有后缀,在config配置文件中没有添加默认后缀 $this->uri->_explode_segments(); //给URI变量segments[]数组赋值。然后来看下RUI中的这个函数_explode_segments():function _explode_segments() //此时 $this->uri_string 应该为 /home/index 或 /admin/class/method { foreach(explode("/", preg_replace("|/*(.+?)/*$|", "\\1", $this->uri_string)) as $val) { //此处的正则是为了去掉 /home/index 或 /admin/class/method 中的第一个/,之前在论坛提问过这里,感谢jeongee大哥为我解答,3Q $val = trim($this->_filter_uri($val));// 过滤片段用于安全 if ($val != '') { $this->segments[] = $val; //把index.php后面的段(即 控制器名和方法名)放入该数组中 } } }
$this->_parse_routes(); //经过这个函数,应该已经给 控制器和方法 赋值了,下面具体看下这个方法吧:
function _parse_routes()
{
if (count($this->routes) == 1)//这里判断$routes数组的元素个数是否为1,显然这里不为1,但是我不明白为什么要判断这个,有什么作用,这里又是一个疑问??
{
$this->_set_request($this->uri->segments);
return;
}
//经过上面这个函数_explode_segments()之后,数组segment中存放的是安全的字符,home,index 或是 admin class method ,现在把他们组合成字符串
$uri = implode('/', $this->uri->segments); // $uri=home/index 或 admin/class/method 并且是安全的字符串
// 逐字匹配,看看路由配置数组中是否有$uri对应的值
if (isset($this->routes[$uri])) //$this->routes[$uri]=$routes[$uri] 是否有类似这种的 $routes[home/index]="home/index"
{
$this->_set_request(explode('/', $this->routes[$uri])); //这里是调用该函数给 $class 和 $method 赋值,先继续往下看,一会在看看这个函数吧 (函数在下面)
return; //这里赋值完之后 returne 退出 后面的程序不再执行。
}
foreach ($this->routes as $key => $val)//此循环是为了判断$uri,符合路由配置规则中的那项,然后将对应的值用/分解为数组,作为这个_set_request函数的参数
{
$key = str_replace(':any', '.+', str_replace(':num', '[0-9]+', $key)); //:num 替换为 [0-9]+ 将 :any 替换为 .+
if (preg_match('#^'.$key.'$#', $uri))
{
// Do we have a back-reference?
if (strpos($val, '$') !== FALSE AND strpos($key, '(') !== FALSE)
{
$val = preg_replace('#^'.$key.'$#', $val, $uri);
}
$this->_set_request(explode('/', $val));//此处又调用了那个函数_set_request
return;
}
}
$this->_set_request($this->uri->segments);
}
现在来看下这个函数,记住传过来的参数可能是array(0=>'home')或array(0=>'home',1=>'index') 或是 array(0=>'admin',1=>'XXX',2=>'xxx')或 array(0=>'admin',1=>'XXX')下面看函数:
function _set_request($segments = array())
{
$segments = $this->_validate_request($segments);
//先说下该 _validate_request 的作用:就是判断 无论 控制器类 是否是在子目录中 都返回 该控制器名称,并给变量$directory 赋值 下面在仔细看该函数。
if (count($segments) == 0)//显然不会执行
{
return;
}
$this->set_class($segments[0]); //设置控制器类名,但是经过上面那个函数,此时的segments数组可能已经变化了。一会在看那个函数(只有控制器在子目录的时候变化)
if (isset($segments[1])) //判断默认方法是否存在
{
// 判断默认路由配置文件下(app/cnf/routes.php)的脚手架索引scaffolding_trigger的配置,不明白这有什么作用,这里也是个疑问??
if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
{
$this->scaffolding_request = TRUE;
unset($this->routes['scaffolding_trigger']);
}
else
{
$this->set_method($segments[1]); // 设置URL中被请求的方法 给$method 赋值
}
}
else
{
$segments[1] = 'index'; //如果 $segments[1] 不存在,即第二、四种URL的 后两个样子
}
$this->uri->rsegments = $segments; //给URI类下的 rsegments 数组赋值为 $rsegments
}
此时也设置了控制器类和方法,然后看下这个函数中调用的这个函数_validate_request传过来的参数和上面一样:array(0=>'home')或array(0=>'home',1=>'index') 或是 array(0=>'admin',1=>'XXX',2=>'xxx')或 array(0=>'admin',1=>'XXX')
function _set_request($segments = array())
{
$segments = $this->_validate_request($segments);
//先说下该 _validate_request 的作用:就是判断 无论 控制器类 是否是在子目录中 都返回 该控制器名称,并给变量$directory 赋值
if (count($segments) == 0)//显然不会执行
{
return;
}
$this->set_class($segments[0]); //设置控制器类名,但是经过上面那个函数,此时的segments数组可能已经变化了。一会在看那个函数(只有控制器在子目录的时候变化)
if (isset($segments[1])) //判断默认方法是否存在
{
// 判断默认路由配置文件下(app/cnf/routes.php)的脚手架索引scaffolding_trigger的配置,不明白这有什么作用,这里也是个疑问??
if ($this->routes['scaffolding_trigger'] == $segments[1] AND $segments[1] != '_ci_scaffolding')
{
$this->scaffolding_request = TRUE;
unset($this->routes['scaffolding_trigger']);
}
else
{
$this->set_method($segments[1]); // 设置URL中被请求的方法 给$method 赋值
}
}
else
{
$segments[1] = 'index'; //如果 $segments[1] 不存在,即第二、四种URL的 后两个样子
}
$this->uri->rsegments = $segments; //给URI类下的 rsegments 数组赋值为 $rsegments
}
此时也设置了控制器类和方法,然后看下这个函数中调用的这个函数_validate_request
传过来的参数和上面一样:array(0=>'home')或array(0=>'home',1=>'index') 或是 array(0=>'admin',1=>'XXX',2=>'xxx')或 array(0=>'admin',1=>'XXX')
function _validate_request($segments)
{
if (file_exists(APPPATH.'controllers/'.$segments[0].EXT)) //判断application/controllers/下是否有 路由类 $segments[0]
{
return $segments; //如果有说明控制器类没有在子目录里面
}
if (is_dir(APPPATH.'controllers/'.$segments[0]))//判断数组APPPATH.'controllers/'.$segments[0]是否为路径
{
$this->set_directory($segments[0]); //此处给变量$directory赋值 为:$segments[0]."/"
$segments = array_slice($segments, 1); //array_slice() 函数在数组中根据条件取出一段值,并返回。例:array_slice(array('aa','ss'), 1)为ss
//那么此处取出 (/目录名/类名)中的类名称,并从新赋值给 $segments 数组
//此处有个疑问:为什么只把类名赋给数组$segments了呢?方法名呢怎么不赋值过去啊。要是传过来的参数为:array('admin','post','manage')
//那么此时不是只把post赋值给$segments[0]了么,方法manage怎么办?不能总是用默认方法吧。是不是我哪里没有理解到或是程序哪里没看明白呢??求解!!!
if (count($segments) > 0) //此处如果小于0,说明url中可能没有控制器名和方法名,所以此种情况 调用默认控制器 默认方法名
{
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].EXT))
{
show_404($this->fetch_directory().$segments[0]);
}
}
else
{
$this->set_class($this->default_controller);
$this->set_method('index');
if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
{
$this->directory = '';
return array();
}
}
return $segments;
}
// 如果程序运行到这里依然没有找到默认路由类 方法 则返回404错误
show_404($segments[0]);
}
|