3gipnet 发表于 2015-12-23 16:00:10

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]
查看完整版本: CodeIgniter源码解析——/system/core/Common.php