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拿配置参数是一样的。