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->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->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[‘b’]=‘b’,那么如果使用分片,那么test.php被加入CI_Config的效果就是成员变量config[‘a’]得到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拿配置参数是一样的。