


CI framework source code reading notes 6 Extension hook Hook.php, cihook.php_PHP tutorial
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没啥方法,倒是可以通过写模板的时候include进去header.php和footer.php,倒是还有听说smarty模板引擎中有模板继承这个概念,可以让你的内容页继承某个页面,那个页面上写着header.php和footer.php,貌似CI是可以使用smarty模板引擎的,不过我没有那样用过,还有,CI有hook(钩子)这个东西,老实说我没用过,不知道它能不能实现。
是记录有多少人进去你的网站还是说点击的某个连接多少次?

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Evaluating the cost/performance of commercial support for a Java framework involves the following steps: Determine the required level of assurance and service level agreement (SLA) guarantees. The experience and expertise of the research support team. Consider additional services such as upgrades, troubleshooting, and performance optimization. Weigh business support costs against risk mitigation and increased efficiency.

The lightweight PHP framework improves application performance through small size and low resource consumption. Its features include: small size, fast startup, low memory usage, improved response speed and throughput, and reduced resource consumption. Practical case: SlimFramework creates REST API, only 500KB, high responsiveness and high throughput

Writing clear and comprehensive documentation is crucial for the Golang framework. Best practices include following an established documentation style, such as Google's Go Coding Style Guide. Use a clear organizational structure, including headings, subheadings, and lists, and provide navigation. Provides comprehensive and accurate information, including getting started guides, API references, and concepts. Use code examples to illustrate concepts and usage. Keep documentation updated, track changes and document new features. Provide support and community resources such as GitHub issues and forums. Create practical examples, such as API documentation.

Choose the best Go framework based on application scenarios: consider application type, language features, performance requirements, and ecosystem. Common Go frameworks: Gin (Web application), Echo (Web service), Fiber (high throughput), gorm (ORM), fasthttp (speed). Practical case: building REST API (Fiber) and interacting with the database (gorm). Choose a framework: choose fasthttp for key performance, Gin/Echo for flexible web applications, and gorm for database interaction.

The learning curve of a PHP framework depends on language proficiency, framework complexity, documentation quality, and community support. The learning curve of PHP frameworks is higher when compared to Python frameworks and lower when compared to Ruby frameworks. Compared to Java frameworks, PHP frameworks have a moderate learning curve but a shorter time to get started.

According to benchmarks, for small, high-performance applications, Quarkus (fast startup, low memory) or Micronaut (TechEmpower excellent) are ideal choices. SpringBoot is suitable for large, full-stack applications, but has slightly slower startup times and memory usage.

In Go framework development, common challenges and their solutions are: Error handling: Use the errors package for management, and use middleware to centrally handle errors. Authentication and authorization: Integrate third-party libraries and create custom middleware to check credentials. Concurrency processing: Use goroutines, mutexes, and channels to control resource access. Unit testing: Use gotest packages, mocks, and stubs for isolation, and code coverage tools to ensure sufficiency. Deployment and monitoring: Use Docker containers to package deployments, set up data backups, and track performance and errors with logging and monitoring tools.

When choosing a Go framework, key performance indicators (KPIs) include: response time, throughput, concurrency, and resource usage. By benchmarking and comparing frameworks' KPIs, developers can make informed choices based on application needs, taking into account expected load, performance-critical sections, and resource constraints.
