CI框架是一个轻量级的框架,所以我试着去看了一下它的核心部分的源码,弄清楚了CI一个运行的流程和整体代码的一个设计是什么样的。下面就是我的一些粗浅的理解。

核心文件

我看的是CI2.2版本,和3.1版本源码有一些不同(主要是代码的优化,其他部分改动不影响我所讲的内容)。

从CI框架的整个运行流程来看,核心文件主要有以下几个(全都是在system/core/下的,3.1版本是在system/core/compat/):

  • CodeIgniter.php:这是CI运行流程的一个文件,从这个文件你可以看到CI运行的一个流程。就像于一个指挥官,控制着CI的运行。它连接了所有核心类和内容,所有核心类和内容因为它才能相互调用。
  • Common.php:公共方法文件。CI并没有使用namespace+psr4来自动加载内容,而是靠Common里的引用方法&load_class来一一加载实例化核心类的,除此之外Common.php还包含了检查php版本、检查写入权限、获取配置等方法。
  • Controller:控制器父类文件。不得不说CI的控制器载入了太多东西,至少所有的核心类和自动载入(不是PSR4,是在autoload.php里配置的内容)类都载入了。所以在子类控制器继承了之后,你发现是如此方便的调用各种核心类和自动载入的类,这也使控制器变得相当的臃肿,不知是好是坏。
  • Other:Config.php、Loader.php、Outout.php、Router.php、URI.php我就不详细说了,因为他们从名字上就知道是干嘛的,都是功能性的组件类,各司其职。


简述CI运行流程

CI的运行流程主要是看CodeIgniter.php,我只说核心的一些东西,具体大家实现看源码就知道了。

  • 首先,入口文件设置环境、系统system目录路径、应用目录路径等一些配置,最后载入CodeIgniter.php
  • 载入Common.php文件,使用其公共方法&load_class载入各种核心类且实例化,并初始化该初始化的
  • 创建&get_instance方法,它是调用父类控制器的静态方法get_instance返回子类控制器对象。这里我就要说一下父类CI_Controller的构造方法里的这段代码了
      foreach(is_loaded() as $var => $class)
      {
          $this->$var =& load_class($class);
      }
      
    is_loaded()方法是在Common里实现的,返回当前所有使用&load_class方法载入的类名(因为&load_class中调用了is_loaded,is_loaded也是引用函数,有参数时将参数传入自身静态变量,无参时返回这个静态变量)。然后再使用& load_class载入并实例化各个已载入的核心类(若类之前使用& load_class加载实例化,则返回已实例化的对象)。
    所以为什么libraries、helpers等一些自定义里写上$var = &get_instance();就能通过这个$var调用框架的核心内容了。所以我们也看到了,CI的控制器很不单纯的呀~
    可能这里有些混乱,可能因为引用函数的缘故,大家可以去搜一搜,看看PHP的引用函数。
  • 在流程中会在一些点挂上钩子hook的挂载点


简述控制器模板输出过程

首先实例化CI_URI生成指定格式的uri,并生成包含控制器名和方法名的变量。CI_Router获取到控制器名和方法名。根据控制器名载入相应的控制器文件。实例化控制器,父类控制器里的构造方法会载入CI_Load类,并调用其一个方法载入所有自动加载项。根据前面的方法名调用控制器相应的方法,最后这个方法调用load->view(),找到相应视图文件生成模板输出,值得注意的是,CI并没有在生成最终模板时就输出,而是存在缓存里交给了Output类,然后一并输出缓存里的内容,这样做的话是为了再视图文件里也可以使用$this->load->view(),实现可以多处输出模板,最终呈现效果,这无疑提高了重用性。