Home  >  Article  >  Backend Development  >  CI framework source code reading notes 6 Extension hook Hook.php, cihook.php_PHP tutorial

CI framework source code reading notes 6 Extension hook Hook.php, cihook.php_PHP tutorial

WBOY
WBOYOriginal
2016-07-13 10:14:50906browse

CI framework source code reading notes 6 Extension hooks Hook.php, cihook.php

The CI framework allows you to add or change the system without modifying the core code of the system. core functions (such as rewriting cache, output, etc.). For example, if hooks are enabled in the system ($config['enable_hooks'] = TRUE; in config.php), by adding specific hooks, the system can trigger specific scripts at specific times:

<span>$hook</span>['post_system'] = <span>array</span><span>(
    </span>'class'     => 'frameLog',
    'function'  => 'postLog',
    'filename'  => 'post_system.php',
    'filepath'   => 'hooks',<span>
);</span>

The above hook defines a post_system hook, which is used for script processing after the final page rendering (the meaning of the parameters can be referred to later or in the manual, and no further explanation will be given here for the time being).

Then the question is:

Let’s look at it step by step.

1. What is a hook

The definition of hook on Baidu Encyclopedia is:

<p><span>钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。</span></p>

We can see several points from the above definition:

2. Predefined hooks in CI

CI provides 7 available preset hook points, which are:

pre_system: refers to the hook in the early stage of system loading

pre_controller: The hook before calling the controller, routing and security checks have been completed

post_controller_constructor: After the controller is instantiated and before any method is called

post_controller: After the controller is fully running

 display_override: override display

cache_override: Rewrite cache

post_system: After the final page is sent to the client

3. Implementation of hooks in CI

The core function of hooks in CI is completed by the Hook component. Let’s look at the class diagram of this component first:

Among them:

enabled: Flag indicating whether the hook function is enabled.

Hooks: Save the list of hooks enabled in the system

in_progress: We will see later that this flag is used to prevent infinite loops caused by mutual calls between hooks.

_construct is the constructor of the Hook component, which calls _initialize to complete the initialization work

 _call_hook: Call _run_hook to call the specified hook program. We have seen before in CodeIgniter.php that _call_hook is the interface actually provided for external calls.

 _run_hook: The function that actually executes the hook program

Before we start, let’s post the structure of the predefined hook. This structure may appear throughout the source code, so we need to know the meaning of the parameters of this structure.

<span>$hook</span>['xx'] = <span>array</span><span>(
    </span>'class'     => 'xx', <span>//</span><span>钩子调用的类名,可以为空</span>
    'function'  => 'xx',<span>//</span><span>钩子调用的函数名</span>
    'filename'  => 'xx',<span>//</span><span>该钩子的文件名</span>
    'filepath'   => 'xx',<span>//</span><span>钩子的目录</span>
    'params'   => 'xx'<span>//</span><span>传递给钩子的参数</span>
);

1. Hook component initialization

_initialize function is used to initialize the hook component. The main tasks of this function are:

(1) Check whether the hook function in the configuration file is enabled, which requires loading Config (configuration management component):

$CFG =& load_class('Config', 'core');

if ($CFG->item('enable_hooks') == FALSE)
{
	return;
}

(2) Load the defined hook list

Similarly, you can set different ENVIRONMENT to enable different hooks. If there are any, the hooks under ENVRIONMENT will be loaded first:

if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
{
    include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
}
elseif (is_file(APPPATH.'config/hooks.php'))
{
	include(APPPATH.'config/hooks.php');
}

(3) Hook inspection. If no hook is set, or the hook format is wrong, no processing will be done and you will exit directly:

if ( ! isset($hook) OR ! is_array($hook))
{
	return;
}

After initialize, the defined hook list is stored in Hook::hooks:

$this->hooks =& $hook;

2. Call specified hook

_call_hook is the interface directly called in the main program. The main tasks of this interface are:

(1). Check whether the hook is enabled and whether the call hook is predefined (if it is not enabled or the call hook does not exist, it will return directly):

if ( ! $this->enabled OR ! isset($this->hooks[$which]))
{
	return FALSE;
}

(2). Check whether multiple hooks are enabled on the same hook point. If so, execute them in sequence:

if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))
{
	foreach ($this->hooks[$which] as $val)
	{
		$this->_run_hook($val);
	}
}

(3). Otherwise, there is only one hook, execute it

else
{
	$this->_run_hook($this->hooks[$which]);
}

_run_hook is the function that actually executes the hook.

3. run to execute a specific hook program

The

_run_hook function is the actual executor of hook. This function receives a predefined hook array as a parameter and is implemented as follows:

(1). If the parameter passed is not an array at all (naturally it is not a valid hook), then return directly:

if ( ! is_array($data))
{
	return FALSE;
}

(2).    检查hook执行状态。

in_progress用于标志当前hook的执行状态。这个参数的主要作用,是防止hook之间的相互调用而导致的死循环。

if ($this->in_progress == TRUE)
{
	return;
}

(3).    Hook的合法性检查。

为了方便讲述,我们再次提出一个预定义的hook需要的参数:

<span>$hook</span>['xx'] = <span>array</span><span>(
    </span>'class'     => 'xx', <span>//</span><span>钩子调用的类名,可以为空</span>
    'function'  => 'xx',<span>//</span><span>钩子调用的函数名</span>
    'filename'  => 'xx',<span>//</span><span>该钩子的文件名</span>
    'filepath'   => 'xx',<span>//</span><span>钩子的目录</span>
    'params'   => 'xx'<span>//</span><span>传递给钩子的参数</span>
);

其中class和params是可选参数,其他3个参数为必选参数,如果不提供,则由于无法准确定位到hook程序,只能直接返回:

if ( ! isset($data['filepath']) OR ! isset($data['filename']))
{
	return FALSE;
}

$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];

if ( ! file_exists($filepath))
{
	return FALSE;
}

(4).   到这里,已经基本确认钩子程序的位置了,这里有两种情况:

a. 预定义的hook中class参数为空,表明使用的是过程式的调用方式,则直接执行hook文件中的function xxx 

b. class参数不为空,提供的是面向对象的方式,则实际的钩子程序是$class->$function .同样,如果既没有设置class,也没有设置function参数,则无法执行hook,直接返回:

$class		= FALSE;
$function	= FALSE;
$params		= '';

/* 获取 hook class */
if (isset($data['class']) AND $data['class'] != '')
{
	$class = $data['class'];
}

/* 获取 hook function */
if (isset($data['function']))
{
	$function = $data['function'];
}

/* 获取传递的 hook 参数 */
if (isset($data['params']))
{
	$params = $data['params'];
}

/* 如果class和function都不存在,则无法定位hook程序,直接返回 */
if ($class === FALSE AND $function === FALSE)
{
	return FALSE;
}

(5).   设置执行标志in_progress,并执行上述两种情况下的hook:

/* 面向对象的设置方式 */
if ($class !== FALSE)
{
	if ( ! class_exists($class))
	{
		require($filepath);
	}

	$HOOK = new $class;
	$HOOK->$function($params);
}
/*  过程式的执行方式 */
else
{
	if ( ! function_exists($function))
	{
		require($filepath);
	}

	$function($params);
}

最后,别忘了在hook执行完之后,设置标识位in_progress为false,并返回执行成功的标志:

$this->in_progress = FALSE;
return TRUE;

Hook组件的完整源码:

_initialize();
		log_message('debug', "Hooks Class Initialized");
	}

	/**
	 * Initialize the Hooks Preferences
	 *
	 * @access	private
	 * @return	void
	 */
	function _initialize()
	{
		$CFG =& load_class('Config', 'core');

		// If hooks are not enabled in the config file
		// there is nothing else to do

		if ($CFG->item('enable_hooks') == FALSE)
		{
			return;
		}

		if (defined('ENVIRONMENT') AND is_file(APPPATH.'config/'.ENVIRONMENT.'/hooks.php'))
		{
		    include(APPPATH.'config/'.ENVIRONMENT.'/hooks.php');
		}
		elseif (is_file(APPPATH.'config/hooks.php'))
		{
			include(APPPATH.'config/hooks.php');
		}

		if ( ! isset($hook) OR ! is_array($hook))
		{
			return;
		}

		$this->hooks =& $hook;
		$this->enabled = TRUE;
	}

	/**
	 * Call Hook
	 *
	 * Calls a particular hook
	 *
	 * @access	private
	 * @param	string	the hook name
	 * @return	mixed
	 */
	function _call_hook($which = '')
	{
		if ( ! $this->enabled OR ! isset($this->hooks[$which]))
		{
			return FALSE;
		}

		if (isset($this->hooks[$which][0]) AND is_array($this->hooks[$which][0]))
		{
			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
	 *
	 * @access	private
	 * @param	array	the hook details
	 * @return	bool
	 */
	function _run_hook($data)
	{
		if ( ! is_array($data))
		{
			return FALSE;
		}

		// If the script being called happens to have the same hook call within it a loop can happen

		if ($this->in_progress == TRUE)
		{
			return;
		}

		if ( ! isset($data['filepath']) OR ! isset($data['filename']))
		{
			return FALSE;
		}

		$filepath = APPPATH.$data['filepath'].'/'.$data['filename'];

		if ( ! file_exists($filepath))
		{
			return FALSE;
		}


		$class		= FALSE;
		$function	= FALSE;
		$params		= '';

		if (isset($data['class']) AND $data['class'] != '')
		{
			$class = $data['class'];
		}

		if (isset($data['function']))
		{
			$function = $data['function'];
		}

		if (isset($data['params']))
		{
			$params = $data['params'];
		}

		if ($class === FALSE AND $function === FALSE)
		{
			return FALSE;
		}

		$this->in_progress = TRUE;

		// Call the requested class and/or function
		if ($class !== FALSE)
		{
			if ( ! class_exists($class))
			{
				require($filepath);
			}

			$HOOK = new $class;
			$HOOK->$function($params);
		}
		else
		{
			if ( ! function_exists($function))
			{
				require($filepath);
			}

			$function($params);
		}

		$this->in_progress = FALSE;
		return TRUE;
	}

}

参考文献

1.  http://codeigniter.org.cn/user_guide/general/hooks.html   手册

2.  http://itopic.org/codeigniter-hook.html  

3.  http://codeigniter.org.cn/forums/thread-4947-1-1.html  钩子实现的Layout

CI框架引入模板问题

这个……好像CI没啥方法,倒是可以通过写模板的时候include进去header.php和footer.php,倒是还有听说smarty模板引擎中有模板继承这个概念,可以让你的内容页继承某个页面,那个页面上写着header.php和footer.php,貌似CI是可以使用smarty模板引擎的,不过我没有那样用过,还有,CI有hook(钩子)这个东西,老实说我没用过,不知道它能不能实现。
 

CI框架 怎实现统计网站点击量,哪位把源码发我跪

是记录有多少人进去你的网站还是说点击的某个连接多少次?
 

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/908124.htmlTechArticleCI框架源码阅读笔记6 扩展钩子 Hook.php,cihook.php CI框架允许你在不修改系统核心代码的基础上添加或者更改系统的核心功能(如重写缓存、...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn