CI框架CI_Router分析

__construct

public function __construct($routing = NULL)
{
	$this->config =& load_class('Config', 'core');
	$this->uri =& load_class('URI', 'core');

	$this->enable_query_strings = ( ! is_cli() && $this->config->item('enable_query_strings') === TRUE);

	// If a directory override is configured, it has to be set before any dynamic routing logic
	is_array($routing) && isset($routing['directory']) && $this->set_directory($routing['directory']);
	$this->_set_routing();

	// Set any routing overrides that may exist in the main index file
	if (is_array($routing))
	{
		empty($routing['controller']) OR $this->set_class($routing['controller']);
		empty($routing['function'])   OR $this->set_method($routing['function']);
	}

	log_message('info', 'Router Class Initialized');
}
首先加载config和uri的核心文件
config:获取用户和系统设定的配置項
URI : 用于请求地址分析
第二步判断是否启用enable_query_strings
必须不能是cli请求
第三步设置自定义路由
开发者在入口文件中定义的
第四步分析路由设置需要执行的类和方法
_set_routing为受保护的方法

_set_routing

protected function _set_routing()
{
	// Load the routes.php file. It would be great if we could
	// skip this for enable_query_strings = TRUE, but then
	// default_controller would be empty ...
	if (file_exists(APPPATH.'config/routes.php'))
	{
		include(APPPATH.'config/routes.php');
	}

	if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/routes.php'))
	{
		include(APPPATH.'config/'.ENVIRONMENT.'/routes.php');
	}

	// Validate & get reserved routes
	if (isset($route) && is_array($route))
	{
		isset($route['default_controller']) && $this->default_controller = $route['default_controller'];
		isset($route['translate_uri_dashes']) && $this->translate_uri_dashes = $route['translate_uri_dashes'];
		unset($route['default_controller'], $route['translate_uri_dashes']);
		$this->routes = $route;
	}

	// Are query strings enabled in the config file? Normally CI doesn't utilize query strings
	// since URI segments are more search-engine friendly, but they can optionally be used.
	// If this feature is enabled, we will gather the directory/class/method a little differently
	if ($this->enable_query_strings)
	{
		// If the directory is set at this time, it means an override exists, so skip the checks
		if ( ! isset($this->directory))
		{
			$_d = $this->config->item('directory_trigger');
			$_d = isset($_GET[$_d]) ? trim($_GET[$_d], " \t\n\r\0\x0B/") : '';

			if ($_d !== '')
			{
				$this->uri->filter_uri($_d);
				$this->set_directory($_d);
			}
		}

		$_c = trim($this->config->item('controller_trigger'));
		if ( ! empty($_GET[$_c]))
		{
			$this->uri->filter_uri($_GET[$_c]);
			$this->set_class($_GET[$_c]);

			$_f = trim($this->config->item('function_trigger'));
			if ( ! empty($_GET[$_f]))
			{
				$this->uri->filter_uri($_GET[$_f]);
				$this->set_method($_GET[$_f]);
			}

			$this->uri->rsegments = array(
				1 => $this->class,
				2 => $this->method
			);
		}
		else
		{
			$this->_set_default_controller();
		}

		// Routing rules don't apply to query strings and we don't need to detect
		// directories, so we're done here
		return;
	}

	// Is there anything to parse?
	if ($this->uri->uri_string !== '')
	{
		$this->_parse_routes();
	}
	else
	{
		$this->_set_default_controller();
	}
}
  • 前面的20行,主要就是加载config/router.php文件中配置的路由规则,以便后面匹配到相应规则的时候,可以执行指定的类和方法
  • 如果启用了enable_query_strings 则他会根据 c=products&m=view&id=345&d=controllers/products
  • 最下面则是如果没有带参数则进入默认的控制器和方法,如果有则对uri进行解析

_parse_routes

protected function _parse_routes()
{
	// Turn the segment array into a URI string
	$uri = implode('/', $this->uri->segments);

	// Get HTTP verb
	$http_verb = isset($_SERVER['REQUEST_METHOD']) ? strtolower($_SERVER['REQUEST_METHOD']) : 'cli';

	// Loop through the route array looking for wildcards
	foreach ($this->routes as $key => $val)
	{
		// Check if route format is using HTTP verbs
		if (is_array($val))
		{
			$val = array_change_key_case($val, CASE_LOWER);
			if (isset($val[$http_verb]))
			{
				$val = $val[$http_verb];
			}
			else
			{
				continue;
			}
		}

		// Convert wildcards to RegEx
		$key = str_replace(array(':any', ':num'), array('[^/]+', '[0-9]+'), $key);

		// Does the RegEx match?
		if (preg_match('#^'.$key.'$#', $uri, $matches))
		{
			// Are we using callbacks to process back-references?
			if ( ! is_string($val) && is_callable($val))
			{
				// Remove the original string from the matches array.
				array_shift($matches);

				// Execute the callback using the values in matches as its parameters.
				$val = call_user_func_array($val, $matches);
			}
			// Are we using the default routing method for back-references?
			elseif (strpos($val, '$') !== FALSE && strpos($key, '(') !== FALSE)
			{
				$val = preg_replace('#^'.$key.'$#', $val, $uri);
			}

			$this->_set_request(explode('/', $val));
			return;
		}
	}

	// If we got this far it means we didn't encounter a
	// matching route so we'll set the site default route
	$this->_set_request(array_values($this->uri->segments));
}
  • 该方法主要用于查看是否有对应的开发者自己定义的路由,如果有的话,则按照开发者定义的路由设置控制器和方法
  • 逻辑如下:循环用户定义的router数组,如果数组中的值也是一个数组,则需要检测是否设置了请求的类型,如果无法匹配到对应的类型,则直接跳过,再检查是否有匹配的请求方式,如果有则按照对应的请求方式请求,没有则按照正常的uri请求

_validate_request

protected function _validate_request($segments)
{

	$c = count($segments);
	$directory_override = isset($this->directory);

	// Loop through our segments and return as soon as a controller
	// is found or when such a directory doesn't exist
	while ($c-- > 0)
	{
		$test = $this->directory
			.ucfirst($this->translate_uri_dashes === TRUE ? str_replace('-', '_', $segments[0]) : $segments[0]);

		if ( ! file_exists(APPPATH.'controllers/'.$test.'.php')
			&& $directory_override === FALSE
			&& is_dir(APPPATH.'controllers/'.$this->directory.$segments[0])
		)
		{
			$this->set_directory(array_shift($segments), TRUE);
			continue;
		}

		return $segments;
	}

	// This means that all segments were actually directories
	return $segments;
}

千万不要因为此方法的名字而产生误会,此方法并不是过滤请求的!!!
此方法为检测出真实controller的地址,因为开发者可能把controller定义为controllers/member/goods.php,就是为了处理前面多了一级member的这种情况,允许多级目录存在

_set_request

protected function _set_request($segments = array())
{
	$segments = $this->_validate_request($segments);
	// If we don't have any segments left - try the default controller;
	// WARNING: Directories get shifted out of the segments array!
	if (empty($segments))
	{
		$this->_set_default_controller();
		return;
	}

	if ($this->translate_uri_dashes === TRUE)
	{
		$segments[0] = str_replace('-', '_', $segments[0]);
		if (isset($segments[1]))
		{
			$segments[1] = str_replace('-', '_', $segments[1]);
		}
	}

	$this->set_class($segments[0]);
	if (isset($segments[1]))
	{
		$this->set_method($segments[1]);
	}
	else
	{
		$segments[1] = 'index';
	}

	array_unshift($segments, NULL);
	unset($segments[0]);

	$this->uri->rsegments = $segments;
}

此方法用于设置程序执行的controller和methods,如果没有参数的,默认执行默认的controller和methods,最为迷惑的是其中这段代码

array_unshift($segments, NULL);
unset($segments[0]);

这两行代码估计是为了让segments数组的key统统+1的操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值