接着Benchmark.php往下看,下一个引入的文件是Hooks.php,我们称之为钩子。它的目的是在不改变核心文件的基础上,来修改框架的内部运作流程。具体使用方法参见手册http://codeigniter.org.cn/user_guide/general/hooks.html。

首先看类里面的几个属性,

public $enabled = FALSE;  用来表示钩子是否可用

public $hooks = array();  配置文件中的信息

protected $_objects = array();  缓存用变量,用来储存挂钩点方法对应的对象

protected $_in_progress = FALSE;  表示当前钩子是否正在进程中

  public function __construct()
{
$CFG =& load_class('Config', 'core');
log_message('info', 'Hooks Class Initialized'); // If hooks are not enabled in the config file
// there is nothing else to do
if ($CFG->item('enable_hooks') === FALSE)
{
return;
} // Grab the "hooks" definition file.
if (file_exists(APPPATH.'config/hooks.php'))
{
include(APPPATH.'config/hooks.php');
} if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
} // If there are no hooks, we're done.
if ( ! isset($hook) OR ! is_array($hook))
{
return;
} $this->hooks =& $hook;
$this->enabled = TRUE;
}

再来看看构造函数,$CFG =& load_class('Config', 'core');是加载config组件,用来获取hook的配置(具体的配置获取流程,我们后面分析Config.php时再详细讨论),log_message('info', 'Hooks Class Initialized');用来在日志中记录调用钩子的信息,注意需要在config.php配置中修改log_threshold的对应等级才能记录,具体原理参见前面的Log.php章节。

再往下判断配置中的enable_hooks属性是否设置为了true,如果没有设置那么不继续往下,所以$this->enabled属性不会置为true,实际上意味着此时钩子功能不生效。

接着引入hooks.php文件,并且获取其中配置,若配置信息格式正确,设置$this->enabled = TRUE;

此时构造函数结束,我们接着看call_hook方法。

  public function call_hook($which = '')
{
if ( ! $this->enabled OR ! isset($this->hooks[$which]))
{
return FALSE;
} if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function']))
{
foreach ($this->hooks[$which] as $val)
{
$this->_run_hook($val);
}
}
else
{
$this->_run_hook($this->hooks[$which]);
} return TRUE;
}

钩子功能的之所以生效是因为我们在Codeigniter.php文件中,多次使用了call_hook方法,该方法的参数我们称之为挂钩点,ci中的挂钩点有7个,具体参见文档,不细述。

先判断enabled属性是否为true,并且相应挂钩点的配置内容是否存在,只有上面两个条件都符合才继续往下。

if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function']))这行代码的目的是判断是否多次调用该挂钩点,ci框架支持挂钩点多次调用,只需要在配置中写成数组形式即可。若是,循环对配置执行_run_hook,如不是就不需要循环。

  protected function _run_hook($data)
{
//判断$data是否时合法的可调用结构,如果是的话直接调用
//主要是为了处理ambda 表达式/匿名函数(或闭包)作为钩子的这种情况
if (is_callable($data))
{
is_array($data)
? $data[0]->{$data[1]}()
: $data(); return TRUE;
}
//如果不是数组,说明配置有问题
elseif ( ! is_array($data))
{
return FALSE;
} //规避当前钩子正在执行其他脚本的情况
if ($this->_in_progress === TRUE)
{
return;
} if ( ! isset($data['filepath'], $data['filename']))
{
return FALSE;
} //文件名赋值
$filepath = APPPATH.$data['filepath'].'/'.$data['filename']; if ( ! file_exists($filepath))
{
return FALSE;
} //读取配置内容赋值变量
$class = empty($data['class']) ? FALSE : $data['class'];
$function = empty($data['function']) ? FALSE : $data['function'];
$params = isset($data['params']) ? $data['params'] : ''; //判断要调用的方法是否存在
if (empty($function))
{
return FALSE;
} //即将调用挂钩点方法,设置_in_progress为true,阻止再次进入脚本执行
$this->_in_progress = TRUE; //判读$class是否为false,目的是判断配置中是否写了class,若没有写,那么可能
//挂钩点的文件不是class的形式,只有一个函数,直接调用即可
if ($class !== FALSE)
{
//先判断挂钩点对应的对象是否存在
if (isset($this->_objects[$class]))
{
if (method_exists($this->_objects[$class], $function))
{
$this->_objects[$class]->$function($params);
}
else
{
return $this->_in_progress = FALSE;
}
}
else
{
//判断类是否定义,若没有定义引入类文件
class_exists($class, FALSE) OR require_once($filepath); //判断类和类中的方法是否存在,若为false,是否钩子的进程变量_in_progress,推出_run_hook方法
if ( ! class_exists($class, FALSE) OR ! method_exists($class, $function))
{
return $this->_in_progress = FALSE;
} //类实例化,并且储存到_objects变量中
$this->_objects[$class] = new $class();
//调用类中的方法
$this->_objects[$class]->$function($params);
}
}
//直接调用文件中的函数
else
{
//检查类是否已经定义,若没有定义那么引入类文件
function_exists($function) OR require_once($filepath); //判断即将调用的方法是否存在,若不存在释放hook进程变量,退出_run_hook方法
if ( ! function_exists($function))
{
return $this->_in_progress = FALSE;
}
//传入参数,调用方法
$function($params);
}
//释放进程变量,返回true,_run_hook方法执行成功
$this->_in_progress = FALSE;
return TRUE;
}

(代码分析写在注释中了)。

Hooks.php文件就是上面的这些内容了,分析完毕,下面贴出全部代码。

class CI_Hooks {

    /**
* Determines whether hooks are enabled
*
* @var bool
*/
public $enabled = FALSE; /**
* List of all hooks set in config/hooks.php
*
* @var array
*/
public $hooks = array(); /**
* Array with class objects to use hooks methods
*
* @var array
*/
protected $_objects = array(); /**
* In progress flag
*
* Determines whether hook is in progress, used to prevent infinte loops
*
* @var bool
*/
protected $_in_progress = FALSE; /**
* Class constructor
*
* @return void
*/
public function __construct()
{
$CFG =& load_class('Config', 'core');
log_message('info', 'Hooks Class Initialized'); // If hooks are not enabled in the config file
// there is nothing else to do
if ($CFG->item('enable_hooks') === FALSE)
{
return;
} // Grab the "hooks" definition file.
if (file_exists(APPPATH.'config/hooks.php'))
{
include(APPPATH.'config/hooks.php');
} if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
{
include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
} // If there are no hooks, we're done.
if ( ! isset($hook) OR ! is_array($hook))
{
return;
} $this->hooks =& $hook;
$this->enabled = TRUE;
} // -------------------------------------------------------------------- /**
* Call Hook
*
* Calls a particular hook. Called by CodeIgniter.php.
*
* @uses CI_Hooks::_run_hook()
*
* @param string $which Hook name
* @return bool TRUE on success or FALSE on failure
*/
public function call_hook($which = '')
{
if ( ! $this->enabled OR ! isset($this->hooks[$which]))
{
return FALSE;
} if (is_array($this->hooks[$which]) && ! isset($this->hooks[$which]['function']))
{
foreach ($this->hooks[$which] as $val)
{
$this->_run_hook($val);
}
}
else
{
$this->_run_hook($this->hooks[$which]);
} return TRUE;
} // -------------------------------------------------------------------- /**
* Run Hook
*
* Runs a particular hook
*
* @param array $data Hook details
* @return bool TRUE on success or FALSE on failure
*/
protected function _run_hook($data)
{
// Closures/lambda functions and array($object, 'method') callables
if (is_callable($data))
{
is_array($data)
? $data[0]->{$data[1]}()
: $data(); return TRUE;
}
elseif ( ! is_array($data))
{
return FALSE;
} // -----------------------------------
// Safety - Prevents run-away loops
// ----------------------------------- // If the script being called happens to have the same
// hook call within it a loop can happen
if ($this->_in_progress === TRUE)
{
return;
} // -----------------------------------
// Set file path
// ----------------------------------- if ( ! isset($data['filepath'], $data['filename']))
{
return FALSE;
} $filepath = APPPATH.$data['filepath'].'/'.$data['filename']; if ( ! file_exists($filepath))
{
return FALSE;
} // Determine and class and/or function names
$class = empty($data['class']) ? FALSE : $data['class'];
$function = empty($data['function']) ? FALSE : $data['function'];
$params = isset($data['params']) ? $data['params'] : ''; if (empty($function))
{
return FALSE;
} // Set the _in_progress flag
$this->_in_progress = TRUE; // Call the requested class and/or function
if ($class !== FALSE)
{
// The object is stored?
if (isset($this->_objects[$class]))
{
if (method_exists($this->_objects[$class], $function))
{
$this->_objects[$class]->$function($params);
}
else
{
return $this->_in_progress = FALSE;
}
}
else
{
class_exists($class, FALSE) OR require_once($filepath); if ( ! class_exists($class, FALSE) OR ! method_exists($class, $function))
{
return $this->_in_progress = FALSE;
} // Store the object and execute the method
$this->_objects[$class] = new $class();
$this->_objects[$class]->$function($params);
}
}
else
{
function_exists($function) OR require_once($filepath); if ( ! function_exists($function))
{
return $this->_in_progress = FALSE;
} $function($params);
} $this->_in_progress = FALSE;
return TRUE;
} }

CI框架源码学习笔记5——Hooks.php的更多相关文章

  1. CI框架源码学习笔记1——index.php

    做php开发一年多了,陆陆续续用过tp/ci/yii框架,一直停留在只会使用的层面上,关于框架内部的结构实际上是不甚了解的.为了深入的学习,决定把CI框架的源码从头到尾的学习一下, 主要因为CI框架工 ...

  2. CI框架源码学习笔记7——Utf8.php

    愉快的清明节假期结束了,继续回到CI框架学习.这一节我们来看看Utf8.php文件,它主要是用来做utf8编码,废话不多说,上代码. class CI_Utf8 { /** * Class const ...

  3. CI框架源码学习笔记2——Common.php

    上一节我们最后说到了CodeIgniter.php,可是这一节的标题是Common.php,有的朋友可能会觉得很奇怪.事实上,CodeIgniter.php其实包含了ci框架启动的整个流程. 里面引入 ...

  4. CI框架源码学习笔记4——Benchmark.php

    我们回到Codeigniter.php上继续往下看,第一个引入的类文件是Benchmark.php,这个文件主要是提供基准测试,具体使用方法参考手册http://codeigniter.org.cn/ ...

  5. CI框架源码学习笔记6——Config.php

    接着上一节往下,我们这一节来看看配置类Config.php,对应手册内容http://codeigniter.org.cn/user_guide/libraries/config.html. clas ...

  6. CI框架源码学习笔记3——Log.php

    上一节说完了Common.php,然而跟代码打交道总是免不了日志记录,所以这一节我们说说Log.php文件. 先看看类里面的几个属性, protected $_log_path;  日志路径 prot ...

  7. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  8. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  9. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

随机推荐

  1. 冷扑大师AI简史:你用德扑来游戏,人家用来发Science

    前言 人类又输了...... 创新工场组织的一场“人工智能和顶尖牌手巅峰表演赛中”,机器人AI冷扑大师赢了人类代表队龙之队 792327 记分牌,最后 200 万奖励归机器人所有. 在围棋项目上人类的 ...

  2. 【新手向】Centos系统文件权限的系统阐述与演示

    在linux服务器日常管理中,我们会经常管理查看文件或者文件夹的权限内容以保证服务的正常运行.今天就和大家聊聊文件权限的那些事. 查看文件的权限情况可以用 ll 命令例: ll -d /kid #查看 ...

  3. ABP模块配置

    介绍 我们知道ABP中模块的配置都是通过模块的Configuration属性来设置的.例如在模块的生命周期方法中可以进行一系列的配置 审计 MQ Redis....也可以替换一些ABP默认配置 通常我 ...

  4. LAMP 2.1Apache不记录指定文件类型日志

    访问日志只需要记地址,不用记录图片. 对无用的图片日志做标记,针对标记做限制.打开 vim /usr/local/apache2/conf/extra/httpd-vhosts.conf 把 Erro ...

  5. DAY13-前端之JavaScript

    JavaScript概述 JavaScript的历史 1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中),后将其改名ScriptEase(客 ...

  6. python爬虫框架(3)--Scrapy框架安装配置

    1.安装python并将scripts配置进环境变量中 2.安装pywin32 在windows下,必须安装pywin32,安装地址:http://sourceforge.net/projects/p ...

  7. 两种布局的ListVIew Adapter。例如微信对话界面

    这个界面  实现的不是微信对话界面.实现的是,focus的状态下,变为放大的另一种布局 重点: 一.定义类型个数 private final int TYPE_COUNT = 2;    privat ...

  8. nginx配置域名

    其他都一样,就特别说下server块的配置. server { listen 80; server_name www.icweshop.com; # 注意:这里你填写的域名必须在/etc/hosts中 ...

  9. 给Activity切换过程添加动画效果

    首先,在资源文件中定义一些动画效果 例如: <scale android:duration="@android:integer/config_mediumAnimTime" ...

  10. Java构造函数中调用构造函数

    在Java中,当为一个类创建了多个构造函数时,有时想在一个构造函数中调用另一个构造函数以减少代码量.这时可以使用this关键字来实现. 通常,当使用this关键字时,它意味着"这个对象&qu ...