缘由
app/controllers/Index.php
中有如下代码
public function disable(){
$this->yredis->set('name','tb');
var_dump($this->yredis->get('name'));
$this->load->view('welcome_message');
}
发现这个yredis没有load,怎么来的?翻翻手册,有自动加载配置
在app/config/autoload.php中配置,部分内容如下
| -------------------------------------------------------------------
| Auto-load Libraries
| -------------------------------------------------------------------
| These are the classes located in system/libraries/ or your
| application/libraries/ directory, with the addition of the
| 'database' library, which is somewhat of a special case.
|
| Prototype:
|
| $autoload['libraries'] = array('database', 'email', 'session');
|
| You can also supply an alternative library name to be assigned
| in the controller:
|
| $autoload['libraries'] = array('user_agent' => 'ua');
*/
$autoload['libraries'] = array('Yredis','validation'=>'sn');
追踪一下
那么他这个自动加载是在代码内如何实现的呢?肯定从头$CI
大对象来看。
在system/core/Controller.php中
,有如下两句
$this->load =& load_class('Loader', 'core');
$this->load->initialize();
通过common.php
中定义的load_class方法,加载了loader类。不得不说ci的核心基本都在这里了。(这个load还是个未定义的属性么...?)
我们去看system/core/Loader.php
中的initialize方法,不过load的时候肯定是先加载__construct
方法
public function __construct()
{
// (ob机制,不要乱配~)
$this->_ci_ob_level = ob_get_level();
$this->_ci_classes =& is_loaded();
log_message('info', 'Loader Class Initialized');
}
再回来看当前文件的initialize方法:
public function initialize()
{
$this->_ci_autoloader();
}
再去看_ci_autoloader...
protected function _ci_autoloader()
{
if (file_exists(APPPATH.'config/autoload.php'))
{
include(APPPATH.'config/autoload.php');
}
if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
}
if ( ! isset($autoload))
{
return;
}
// Autoload packages
if (isset($autoload['packages']))
{
foreach ($autoload['packages'] as $package_path)
{
$this->add_package_path($package_path);
}
}
// Load any custom config file
if (count($autoload['config']) > 0)
{
foreach ($autoload['config'] as $val)
{
$this->config($val);
}
}
// Autoload helpers and languages
foreach (array('helper', 'language') as $type)
{
if (isset($autoload[$type]) && count($autoload[$type]) > 0)
{
$this->$type($autoload[$type]);
}
}
// Autoload drivers
if (isset($autoload['drivers']))
{
$this->driver($autoload['drivers']);
}
// Load libraries
if (isset($autoload['libraries']) && count($autoload['libraries']) > 0)
{
// Load the database driver.
if (in_array('database', $autoload['libraries']))
{
$this->database();
$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
}
// Load all other libraries
$this->library($autoload['libraries']);
}
// Autoload models
if (isset($autoload['model']))
{
$this->model($autoload['model']);
}
}
这里总算有点眉目,定位到了加载开头配置的autoload.php
的位置,include(APPPATH.'config/autoload.php')
;
不难得出,是分别处理配置段的packages,config,helper,language,dirvers,libraries
(包含database在内),我们只是看library,于是定位到
$this->library($autoload['libraries']);
这里,看library方法
public function library($library, $params = NULL, $object_name = NULL)
{
if (empty($library))
{
return $this;
}
elseif (is_array($library))
{
foreach ($library as $key => $value)
{
if (is_int($key))
{
$this->library($value, $params);
}
else
{
$this->library($key, $params, $value);
}
}
return $this;
}
if ($params !== NULL && ! is_array($params))
{
$params = NULL;
}
$this->_ci_load_library($library, $params, $object_name);
return $this;
}
froeach中的if else 就是判断是否使用了别名,就像开头在autoload.php
中配置$autoload['libraries'] = array('Yredis','validation'=>'sn')
;的第二个参数那样,这样我们在项目中可以显示使用$this->sn->xx()
执行了。当然到这还没完,虽然最后返回的是$this
,但是之前执行了关键的一步
$this->_ci_load_library($library, $params, $object_name);
我们继续看_ci_load_library
方法
protected function _ci_load_library($class, $params = NULL, $object_name = NULL)
{
// Get the class name, and while we're at it trim any slashes.
// The directory path can be included as part of the class name,
// but we don't want a leading slash
$class = str_replace('.php', '', trim($class, '/'));
// Was the path included with the class name?
// We look for a slash to determine this
if (($last_slash = strrpos($class, '/')) !== FALSE)
{
// Extract the path
$subdir = substr($class, 0, ++$last_slash);
// Get the filename from the path
$class = substr($class, $last_slash);
}
else
{
$subdir = '';
}
$class = ucfirst($class);
// Is this a stock library? There are a few special conditions if so ...
if (file_exists(BASEPATH.'libraries/'.$subdir.$class.'.php'))
{
return $this->_ci_load_stock_library($class, $subdir, $params, $object_name);
}
// Safety: Was the class already loaded by a previous call?
if (class_exists($class, FALSE))
{
$property = $object_name;
if (empty($property))
{
$property = strtolower($class);
isset($this->_ci_varmap[$property]) && $property = $this->_ci_varmap[$property];
}
$CI =& get_instance();
if (isset($CI->$property))
{
log_message('debug', $class.' class already loaded. Second attempt ignored.');
return;
}
return $this->_ci_init_library($class, '', $params, $object_name);
}
// Let's search for the requested library file and load it.
foreach ($this->_ci_library_paths as $path)
{
// BASEPATH has already been checked for
if ($path === BASEPATH)
{
continue;
}
$filepath = $path.'libraries/'.$subdir.$class.'.php';
// Does the file exist? No? Bummer...
if ( ! file_exists($filepath))
{
continue;
}
include_once($filepath);
return $this->_ci_init_library($class, '', $params, $object_name);
}
// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
if ($subdir === '')
{
return $this->_ci_load_library($class.'/'.$class, $params, $object_name);
}
// If we got this far we were unable to find the requested class.
log_message('error', 'Unable to load the requested class: '.$class);
show_error('Unable to load the requested class: '.$class);
}
大家可以看多个return的前导条件,我们最后追到_ci_init_library
方法。如下:
protected function _ci_init_library($class, $prefix, $config = FALSE, $object_name = NULL)
{
// Is there an associated config file for this class? Note: these should always be lowercase
if ($config === NULL)
{
// Fetch the config paths containing any package paths
$config_component = $this->_ci_get_component('config');
if (is_array($config_component->_config_paths))
{
$found = FALSE;
foreach ($config_component->_config_paths as $path)
{
// We test for both uppercase and lowercase, for servers that
// are case-sensitive with regard to file names. Load global first,
// override with environment next
if (file_exists($path.'config/'.strtolower($class).'.php'))
{
include($path.'config/'.strtolower($class).'.php');
$found = TRUE;
}
elseif (file_exists($path.'config/'.ucfirst(strtolower($class)).'.php'))
{
include($path.'config/'.ucfirst(strtolower($class)).'.php');
$found = TRUE;
}
if (file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
{
include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
$found = TRUE;
}
elseif (file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
{
include($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');
$found = TRUE;
}
// Break on the first found configuration, thus package
// files are not overridden by default paths
if ($found === TRUE)
{
break;
}
}
}
}
$class_name = $prefix.$class;
// Is the class name valid?
if ( ! class_exists($class_name, FALSE))
{
log_message('error', 'Non-existent class: '.$class_name);
show_error('Non-existent class: '.$class_name);
}
// Set the variable name we will assign the class to
// Was a custom class name supplied? If so we'll use it
if (empty($object_name))
{
$object_name = strtolower($class);
if (isset($this->_ci_varmap[$object_name]))
{
$object_name = $this->_ci_varmap[$object_name];
}
}
// Don't overwrite existing properties
$CI =& get_instance();
if (isset($CI->$object_name))
{
if ($CI->$object_name instanceof $class_name)
{
log_message('debug', $class_name." has already been instantiated as '".$object_name."'. Second attempt aborted.");
return;
}
show_error("Resource '".$object_name."' already exists and is not a ".$class_name." instance.");
}
// Save the class name and object name
$this->_ci_classes[$object_name] = $class;
var_dump($class);
// Instantiate the class
$CI->$object_name = isset($config)
? new $class_name($config)
: new $class_name();
}
注意多条件下的大小写处理(strtolower
,ucfirst
),等想出坑(如果有)的时候别忘记这里就好。走到最后就是这关键货
$CI->$object_name = isset($config)
? new $class_name($config)
: new $class_name();
到这里就很清楚了,最后参考CI大对象,输出部分如下
//...
["load"]=>
&object(Api_Loader)#13 (12) {
["_ci_services_paths":protected]=>
array(1) {
[0]=>
string(45) "/usr/share/nginx/xin_mount_dev/trunk/app/"
}
["_ci_services":protected]=>
array(0) {
}
["_ci_ob_level":protected]=>
int(1)
["_ci_view_paths":protected]=>
array(1) {
["/usr/share/nginx/xin_mount_dev/trunk/app/views/"]=>
bool(true)
}
["_ci_library_paths":protected]=>
array(2) {
[0]=>
string(45) "/usr/share/nginx/xin_mount_dev/trunk/app/"
[1]=>
string(24) "/usr/share/nginx/ci_3.0/"
}
["_ci_model_paths":protected]=>
array(1) {
[0]=>
string(45) "/usr/share/nginx/xin_mount_dev/trunk/app/"
}
["_ci_helper_paths":protected]=>
array(2) {
[0]=>
string(45) "/usr/share/nginx/xin_mount_dev/trunk/app/"
[1]=>
string(24) "/usr/share/nginx/ci_3.0/"
}
["_ci_cached_vars":protected]=>
array(0) {
}
["_ci_classes":protected]=>
&array(15) {
["benchmark"]=>
string(9) "Benchmark"
["hooks"]=>
string(5) "Hooks"
["config"]=>
string(6) "Config"
["log"]=>
string(3) "Log"
["utf8"]=>
string(4) "Utf8"
["uri"]=>
string(3) "URI"
["router"]=>
string(6) "Router"
["output"]=>
string(6) "Output"
["security"]=>
string(8) "Security"
["input"]=>
string(5) "Input"
["lang"]=>
string(4) "Lang"
["loader"]=>
string(6) "Loader"
["yredis"]=>
string(6) "Yredis"
["sn"]=>
string(10) "Validation"
}
["_ci_models":protected]=>
array(0) {
}
["_ci_helpers":protected]=>
array(0) {
}
["_ci_varmap":protected]=>
array(2) {
["unit_test"]=>
string(4) "unit"
["user_agent"]=>
string(5) "agent"
}
}
["yredis"]=>
object(Yredis)#14 (2) {
["_redis":"Yredis":private]=>
object(Redis)#15 (0) {
}
["_redis_conf":"Yredis":private]=>
array(2) {
["hostname"]=>
string(9) "127.0.0.1"
["port"]=>
string(4) "6379"
}
}
["sn"]=>
object(Validation)#16 (6)
// ...
关注yredis和sn就更清楚啦,注意sn是别名,而实际指向的是Validation这个类
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。