CodeIgniter源码解析——/system/core/Common.php
在阿里一面的时候,面试官问我知道php的设计模式吗,我在面试之前只匆匆看了下工厂模式,其他都没有看,没有答上来。面试结束后,我Google到一篇讲php设计模式很好的博客,大家感兴趣的可以看下。链接是:http://yansu.org/2014/04/19/design-patterns-of-php.html。
距离二面的时间有限,我只看了工厂模式,单例模式,适配器模式,和观察者模式。在看完这几个后,我突然感觉可以去尝试看下大二使用的ci框架的源码。之前因为赶项目和自己水平有限的原因,尝试查看源代码的时候,完全搞不懂框架的设计者这么写代码的意图为何。
即将大四的今天,在初步看了几个设计模式之后,我发现自己渐渐能窥探出一丝框架设计者代码的艺术感,虽然感觉自己可能是管中窥豹,但还是压抑不住这种有些豁然开朗的激动,想把这个感觉很棒的部分记录下来。
1 CodeIgniter(以下简称ci)的运行流程
ci在启动的第一步,是执行index.php文件,该文件定义了许多变量以及需要加载的模块的路径的设置,并在最后引入了/core/CodeIgniter.php,
这个文件可以说是整个ci运行的流程,有位分析ci源代码的大牛说,将这个文件运行一遍,基本上算是完成了整个CI框架的一次完成运行过程,但我在1个小时之前才去分析源代码,运行整个CI的具体流程我还不知,但是在/core/CodeIgniter.php中引用了一个公共函数文件,位于/core/Common.php
2Common.php文件
可以看下该文件中的官方介绍:
[*]/**
[*] * Common Functions
[*] *
[*] * Loads the base classes and executes the request.
[*] *
[*] * @package CodeIgniter
[*] * @subpackage CodeIgniter
[*] * @category Common Functions
[*] * @author EllisLab Dev Team
[*] * @link http://codeigniter.com/user_guide/
[*] */
意思是说该文件定义了一些公共函数,用来加载基本的类和执行请求。
其中有一个&load_class的函数是整个文件的核心。
3 &load_class
以下是该函数的定义。
[*]// ------------------------------------------------------------------------
[*]
[*]if ( ! function_exists('load_class'))
[*]{
[*] /**
[*] * Class registry
[*] *
[*] * This function acts as a singleton. If the requested class does not
[*] * exist it is instantiated and set to a static variable. If it has
[*] * previously been instantiated the variable is returned.
[*] *
[*] * @param string the class name being requested
[*] * @param string the directory where the class should be found
[*] * @param string an optional argument to pass to the class constructor
[*] * @return object
[*] */
[*] function &load_class($class, $directory = 'libraries', $param = NULL)
[*] {
[*] static $_classes = array();
[*]
[*] // Does the class exist? If so, we're done...
[*] if (isset($_classes[$class]))
[*] {
[*] return $_classes[$class];
[*] }
[*]
[*] $name = FALSE;
[*]
[*] // Look for the class first in the local application/libraries folder
[*] // then in the native system/libraries folder
[*] foreach (array(APPPATH, BASEPATH) as $path)
[*] {
[*] if (file_exists($path.$directory.'/'.$class.'.php'))
[*] {
[*] $name = 'CI_'.$class;
[*]
[*] if (class_exists($name, FALSE) === FALSE)
[*] {
[*] require_once($path.$directory.'/'.$class.'.php');
[*] }
[*]
[*] break;
[*] }
[*] }
[*]
[*] // Is the request a class extension? If so we load it too
[*] if (file_exists(APPPATH.$directory.'/'.config_item('subclass_prefix').$class.'.php'))
[*] {
[*] $name = config_item('subclass_prefix').$class;
[*]
[*] if (class_exists($name, FALSE) === FALSE)
[*] {
[*] require_once(APPPATH.$directory.'/'.$name.'.php');
[*] }
[*] }
[*]
[*] // Did we find the class?
[*] if ($name === FALSE)
[*] {
[*] // Note: We use exit() rather then show_error() in order to avoid a
[*] // self-referencing loop with the Exceptions class
[*] set_status_header(503);
[*] echo 'Unable to locate the specified class: '.$class.'.php
该函数首先是一个单例模式的模型,当静态变量的数组中已经加载了该类,则返回引用,如果没有则引入类文件并初始化该类。调用这个函数时自始至终都是返回那个静态数组是单例的。
其次,对需要加载并且实例化的类,并不是在哪里需要的时候require_once来引入,并用new来实例化,而是类似工厂的模式,统一的进行实例化,并且存储在静态数组里,这就使得在ci运行过程中同样一个类只被实例化了一次。
最后,Common.php中还定义了一个&is_loaded的函数,用来记录已经被初始化的类,代码如下:
[*]if ( ! function_exists('is_loaded'))
[*]{
[*] /**
[*] * Keeps track of which libraries have been loaded. This function is
[*] * called by the load_class() function above
[*] *
[*] * @param string
[*] * @return array
[*] */
[*] function &is_loaded($class = '')
[*] {
[*] static $_is_loaded = array();
[*]
[*] if ($class !== '')
[*] {
[*] $_is_loaded[strtolower($class)] = $class;
[*] }
[*]
[*] return $_is_loaded;
[*] }
[*]}
该方法也是使用一个单例,使用静态数组保存已经加载的类,我感觉有些观察者模式的思想。它跟踪着已经加载的类的状态。
页:
[1]