|
在阿里一面的时候,面试官问我知道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
2 Common.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;
- }
- }
该方法也是使用一个单例,使用静态数组保存已经加载的类,我感觉有些观察者模式的思想。它跟踪着已经加载的类的状态。 |
|
|