分析ThinkPHP源码中的设计模式。
设计模式本身就是是否理论性的东西。而我觉得,视频教程应该注重演示操作性的东西,估计一个视频教程全是理论的话, 很多人看着看着就会睡着的。所以,我特意在视频的开始引入一个实例,通过实例说明分析ThinkPHP源码的重要性,说明PHP设计模式好处。
但是自我感觉效果不怎么好, 这个题材,本身理论性太强。而我理论的讲得太少,估计很多人都无法理解我的视频。而如何理论太多了,我觉得还不如写成一篇文章,视频多此一举了(而且我这人不是会说型了,说不了这么多话)。
视频的第一部分:一个实际的例子,已经录好了。播放http://v.youku.com/v_playlist/f5572559o1p0.html(估计会有点让你费解)
这种视频应该怎么录制,希望大家给我点建议。
至于第二部分的内容。我还是先写成文章吧。
1,对Action类的分析:
注:UML图形只体现了类的部分属性和方法,如果全部体现出来,图片就太大了。
图解:
(1)IndexAction,OtherAction表示用户自己建立的一系列控制器,这些控制器都会继承于Action类。
(2)Action,控制基类。他的文件地址位于:ThinkPHP/Lib/Think/Core/Action.class.php。他的主要 功能为:页面操作(如地址转向等,返回ajax等)、视图控制(如指派变量、渲染模版等)。它的视图控制的功能又委托于View类来完成。图中表示出了 Action和View是组合关系。Action的view属性用于存储实例化了的View对象,这里实例化是在Action构造函数中进行,创建对象过 程委托于了Think:instance()方法,这是典型的“工厂模式”,Think:instance()就是创建对象的工厂。再仔细看看源码,会发 现Think:instance()原来是一个专门创建“单例对象”的工厂。View对象其实是个单例,它只会被实例化一次。
(3)View,视图输出。文件位置/Lib/Think/Core/View.class.php 。他的主要功能为输出控制(指派模版变量,模版内容替换等)、解析模版。具体解析模版的过程委托于其他类的,这里可选择是TemplateThink还是 TemplateSmarty或者是其他自己新增的模版解析类来完成解析。这里是一个“策略模式”。View可以创建单例对象,而且它还有assign方 法用于设置值, get方法用户获得值。这是一个典型的“注册模式”拥有的特征。。虽然ThinkPHP并没有把View当作注册表来用。但是因为View又此特性。 使得我们可以在任何地方访问和设置模版变量。比如:我们可以在Model中设置模版变量,只需要 Think:instance("View")->assign("valname","val");也可以用 Think:instance("View")->get("name");来获得Action中指派的模版变量。View类的这个特点也许会为我 们以后解决一些特定问题带来很多帮助。
(4)下面简单说说模版解析类。ThinkPHP默认为选择TemplateThink作为解析模版的策略。TemplateThink又会被解析 的过程委托于ThinkTemplate。 ThinkTemplate就专门负责解析了。它会先解析XML标签,再解析{ }标签。这就是为什么自定义标签中reture部分的PHP语法必须使用PHP替代语法的原因。因为PHP的正常语言也有很多{ }。 这会误导{ }标签的解析。XML标签具体的解析方法是委托于特定的TagLib库类的。
2,对Model类
图解:
(1)ViewModel视图模型, RelationModel关联模型,AdvModel高级模型这些模型都是继承于Model的。这三个拓展模型的实现,都是通过重载父类的方法。
(2)Model类,文件地址:ThinkPHP/Lib/Think/Core/Model.class.php。他的主要功能,进行相关数据表 的ORM和CURD操作。 其实真正对数据库操作的是Db类。Model类只是负责 如:在操作数据库前对数据进行处理、过滤等。再操作数据库后对结果进行处理、判断等。可以说Model类是Db类的装饰器, 这里是一个“装饰模型”。 model中的switchModel方法和setProperty方法给我们的开发来看了很多的灵活性。下面演示一个综合模 型的例子,在一个模型中即能定义视图模型的属性也能高级模型,关联模型和普通模型的属性。
class YourModel extends Model{
//定义视图模型的属性
protected $viewFields = array();
//定义管理模型的属性
protected $_link = array();
//定义高级模型的属性
protected $optimLock = 'lock_version';
protected $returnType = 'array';
protected $blobFields = array();
protected $blobValues = null;
protected $serializeField = array();
protected $readonlyField = array();
protected $_filter = array();
//定义普通模型的属性。
protected $_validate = array();
protected $_auto = array();
protected $_map = array();
public function tomodel($model){
//定义各个模型要传递的属性。
$marr=array(
'View'=>array('options','name','viewFields'),
'Adv'=>array('options','data','name','_validate','_auto','_map','optimLock','returnType','blobFields','serializeField','readonlyField','_filter '),
'Relation'=>array('options','data','name','_link'),
);
$model=ucwords(strtolower($model));
return $this->switchModel($model,$marr[$model]);
}
}
?>
调用tomodel方法实现模式切换, 这和单独使用switchModel是不一样的。
(3)Db类,功能:对数据库进行操作。 Db类永远只能实例话它的子类。 因为不管你是用new 还是用getInstance, 它都讲传递到factory 工厂中生成对象。这个工厂会根据配置文件,觉得Db类到底实例化那个子类, 这就使我们能通过配置文件来指定数据库类型。
3,App类
ThinkPHP的App类,在企业模式中称之为前端控制器。它负责接受请求、初始化系统和调用指定控制器等。前端控制器的代码一般在框架中是固定的,不 会让用户去继承它或者使用调用它的功能。所以对于框架使用者来说,前端控制器是陌生的,只要研究框架的人才会去了解它。
ThinkPHP在调用App类之前会先执行ThinkPHP.php中的代码, 这个文件主要是判断系统是否有核心编译~runtime缓存,如果没有则进行编译。 加载了~runtime缓存后 再会执行App:run的方法,App:run先会对系统进行初始化工作,由App::init()来完成, 初始化时会依赖与Dispatcher类来对网址进行分析处理。图中展示了App和DispatCher的依赖关系。读取系统配置信息也是在这处理话时完 成的。初始化后再又App::exec方法去执行具体的Action控制器。
在App类中,暗藏着类似“观察者模式”中的“观察者”的东西。在初始化后tag('app_init')标签。在执行时有 tag('app_run');标签,在运行结束后有tag('app_end');标签。虽说App一般固定不动,但是我们可以利用这些标签对App进 行拓展, 比如我们在系统初始化时可以加入一个行为插件,判断是电脑端还是手机端。进而配置不同的主题目录, 这样就能快速做出一个手机版网站。