CI 之加载使用 config 文件的几种方式

1,209 阅读4分钟

CI 之加载使用 config 文件的几种方式

config 是 Ci 中的配置文件,其中有自定义的 config ,也有CI框架中带着的config,其中最特殊的当属于config目录下的config.php这个文件了。从官方手册上我们看到,加载config文件大概有两种方式,第一种是使用Core/Config.php 这个文件中的CI_Config类中的load方法加载,第二种是使用CI_Loader::config()方法加载,但是我们仔细观察。CI_Loader::config()方法中的方法

public function config($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)
	{
		$CI =& get_instance();
		$CI->config->load($file, $use_sections, $fail_gracefully);
	}

不难看出,加载器中的config方法最终还是调用了CI_Config类中的load方法来加载config文件中的参数的。

所以我们可以总结,在CI_Controller 或者是 CI_Model的子类中可以通过this->config->load()方法或者是this->load->config()方法,都可以对配置文件进行加载。

至于为什么我在文章一开始说config.php这个文件很特殊,因为这个文件不是通过我上述所说的两种加载配置文件加载的,而是在CI_Config这个类被实例化的时候




function __construct()
	{
		$this->config =& get_config();
		log_message('debug', "Config Class Initialized");

		// Set the base_url automatically if none was provided
		if ($this->config['base_url'] == '')
		{
			if (isset($_SERVER['HTTP_HOST']))
			{
				$base_url = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
				$base_url .= '://'. $_SERVER['HTTP_HOST'];
				$base_url .= str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);
			}

			else
			{
				$base_url = 'http://localhost/';
			}

			$this->set_item('base_url', $base_url);
		}
	}

通过调用Common中的方法get_config()来加载进成员变量config数组(也是后续拿配置文件中参数的的关键变量)

进入common文件中的get_config()这个方法仔细观察可以发现




function &get_config($replace = array())
	{
		static $_config;

		if (isset($_config))
		{
			return $_config[0];
		}

		// Is the config file in the environment folder?
		if ( ! defined('ENVIRONMENT') OR ! file_exists($file_path = APPPATH.'config/'.ENVIRONMENT.'/config.php'))
		{
			$file_path = APPPATH.'config/config.php';
		}

		// Fetch the config file
		if ( ! file_exists($file_path))
		{
			exit('The configuration file does not exist.');
		}

		require($file_path);

		// Does the $config array exist in the file?
		if ( ! isset($config) OR ! is_array($config))
		{
			exit('Your config file does not appear to be formatted correctly.');
		}

		// Are any values being dynamically replaced?
		if (count($replace) > 0)
		{
			foreach ($replace as $key => $val)
			{
				if (isset($config[$key]))
				{
					$config[$key] = $val;
				}
			}
		}

		return $_config[0] =& $config;
	}

这个方法会优先从环境变量目录下找config文件。

好奇的朋友可能会问到,CI_Config这个是什么时候被初始化放入CI_Controller类中的。

我们仔细看CI框架中十分关键的一个文件CodeIgniter.php中可以发现

这个文件中调用了

/*
 * ------------------------------------------------------
 *  Instantiate the config class
 * ------------------------------------------------------
 */
	$CFG =& load_class('Config', 'core');

common中的load_class函数来初始化了CI_Config类,并且会将用load_class这个函数加载的类放入缓存中。而在CI_Controller初始化的时候

	public function __construct()
	{
		self::$instance =& $this;
		
		// Assign all the class objects that were instantiated by the
		// bootstrap file (CodeIgniter.php) to local class variables
		// so that CI can run as one big super object.
		foreach (is_loaded() as $var => $class)
		{
			$this->$var =& load_class($class);
		}

		$this->load =& load_class('Loader', 'core');

		$this->load->initialize();
		
		log_message('debug', "Controller Class Initialized");
	}

又会将load_class函数中加载的类传入到自己的成员变量中,这也就是为什么我们可以在CI_Controller的子类中直接调用this->loadthis->config 等等。那么,load方法具体是怎么加载config的呢,仔细观察CI_Config的load方法,发现

	/**
	 * Load Config File
	 *
	 * @access	public
	 * @param	string	the config file name
	 * @param   boolean  if configuration values should be loaded into their own section
	 * @param   boolean  true if errors should just return false, false if an error message should be displayed
	 * @return	boolean	if the file was loaded correctly
	 */
	function load($file = '', $use_sections = FALSE, $fail_gracefully = FALSE)

load方法除了file文件名外还有两个其他的bool参数,其中最后一个是文件加载失败时打印是否打印错误的选项,那么中间一个叫做使用分片的参数是干什么的呢?我们自习观察load代码后发现,load代码在经过对文件存在的检查过后

            foreach ($check_locations as $location) {
                $file_path = $path . 'config/' . $location . '.php';

                if (in_array($file_path, $this->is_loaded, TRUE)) {
                    $loaded = TRUE;
                    continue 2;
                }

                if (file_exists($file_path)) {
                    $found = TRUE;
                    break;
                }
            }

            if ($found === FALSE) {
                continue;
            }

            include($file_path);

            if (!isset($config) OR !is_array($config)) {
                if ($fail_gracefully === TRUE) {
                    return FALSE;

                    show_error('Your ' . $file_path . ' file does not appear to contain a valid configuration array.');
                }

                if ($use_sections === TRUE) {
                    if (isset($this->config[$file])) {
                        $this->config[$file] = array_merge($this->config[$file], $config);
                    } else {
                        $this->config[$file] = $config;
                    }
                } else {
                    $this->config = array_merge($this->config, $config);
                }

                $this->is_loaded[] = $file_path;
                unset($config);

                $loaded = TRUE;
                log_message('debug', 'Config file loaded: ' . $file_path);
                break;
            }

最终会include文件后,将配置文件中的具体配置信息放入成员变量config中,但是根据方法中间传入的那个参数use_sections的不同,加入成员变量config的方法也不同。

如果use_sections为true,那么文件中的$config数组会被加入成员变量config[文件名]。

如果use_sections为false,那么文件中的$config数组会被merge进入成员变量config。

打个比方有一个config配置文件名字叫test.php其中有变量config[‘a’]=‘a’,config[‘b’]=‘b’,那么如果使用分片,那么test.php被加入CI_Config的效果就是成员变量config[‘test’][‘a’];没有使用分片那么就是可以通过config[‘a’]得到config[‘b’]test.php中的两个变量,当然,如果原成员变量config中已经有’a’这个key 那么后来的就会把先来的覆盖掉。究竟用不用分片取决于具体情况。

那么如何使用加载过的config中的变量呢?虽然CI_Config中的config是public的访问级别,但是比起直接使用成员变量还有一个更优雅的方法,CI_Config给我们提供了一个item()方法

	/**
	 * Fetch a config file item
	 *
	 *
	 * @access	public
	 * @param	string	the config item name
	 * @param	string	the index name
	 * @param	bool
	 * @return	string
	 */
	function item($item, $index = '')
	{
		if ($index == '')
		{
			if ( ! isset($this->config[$item]))
			{
				return FALSE;
			}

			$pref = $this->config[$item];
		}
		else
		{
			if ( ! isset($this->config[$index]))
			{
				return FALSE;
			}

			if ( ! isset($this->config[$index][$item]))
			{
				return FALSE;
			}

			$pref = $this->config[$index][$item];
		}

		return $pref;
	}

来访问成员变量config,因为这个方法比较简单,就不多赘述啦。

当然,除此之外,我们还可以使用公用方法Common中的config_item()函数来得到加载进成员变量config中的参数,因为在CI_Config初始化的时候

	function __construct()
	{
		$this->config =& get_config();
	}

把公共方法get_config()的引用赋给了config成员变量,而config_item()函数最终其实也是去

/**
* Returns the specified config item
*
* @access	public
* @return	mixed
*/
if ( ! function_exists('config_item'))
{
	function config_item($item)
	{
		static $_config_item = array();

		if ( ! isset($_config_item[$item]))
		{
			$config =& get_config();

			if ( ! isset($config[$item]))
			{
				return FALSE;
			}
			$_config_item[$item] = $config[$item];
		}

		return $_config_item[$item];
	}
}

get_config中拿配置参数,其实效果和从CI_Config中成员变量$config拿配置参数是一样的。