0.前言
本文会从搭建WAMP环境开始,描述如何开发自己的个人博客。虽然目前Wordpress已经非常完善、功能非常强大,但对于喜欢简洁的朋友来说似乎有点臃肿。对于刚刚看完PHP语法,苦于没有项目实践的朋友,本文也是一个非常好的台阶。
目前PHP在Web开发方面已经非常流行。可是还有一部分开发人员对PHP的应用还是停留在ASP的阶段。直接将PHP代码和HTML代码混合在同一个文件中。这对于网站的后期维护是非常苦难的,甚至2、3个月后自己写的代码就不认得了。目前PHP有许多框架可以解决以上的问题,例如轻量级的ThinkPHP等、重量级的Zend Framework。对于一些小型的项目,框架可能显得有点“牛刀”。这时,我们就需要自己实现一个简单的MVC框架。这样即可简化后期代码的维护,也可避免框架的学习成本。对于你经常使用的东西,还可以抽象出来,做一个属于自己的框架。这也是本文编写的一个目的。
另:本文会介绍如何搭建开发环境,但每位读者的机器环境不尽相同。只能起指导的作用,具体的问题还是需要google。
1.搭建开发环境
1.1.Apache的安装
Apache的安装比较简单,可以直接从官方网站下载安装。安装过程比较简单,一路按Next就可以了(请根据自己的情况调整安装路径,下文假设Apache安装在D:\prg\Apache Software Foundation\Apache2.2)。
1.2.MySQL的安装
MySQL 同样提供msi的安装包,目前GA的版本是5.1.42,同样可以在mysql官网上找到。安装的过程同样也是一路按Next即可,基本没什么大问题,下文假设MySQL安装在D:\prg\MySQL\MySQL Server 5.0。
1.3.数据库管理工具
在其他文章中会推荐适用phpMyAdmin作为MySQL的管理工具。但就我个人而已,不太喜欢Web方式的数据库管理工具。都已经是本机了,为什么不用C/S的工具呢?我觉得有一个工具比较好用的,叫Navicat MySQL。虽然是一个商业工具,但对个人有免费版,一般功能都有了。安装过程也是比较简单,不作详细叙述。
1.4.PHP5配置
PHP和Apache的配置方式有很多种,我以前使用的方式需要往system32文件夹扔一些文件。这种方法非常不好,再重装以后都需要重新配置,很麻烦。这里介绍一个环境变量的配置方法。
解压PHP,本文假设PHP5解压在D:\prg\PHP5中。
设置环境变量:右击我的电脑->属性->高级->环境变量,找到一个名为Path的环境变量。在最后添加PHP5的路径,以分号(;)分割每个路径。
设置Apache的httpd.conf文件:打开Apache目录下conf\httpd.conf文件:
找到最后一行LoadModule,加入一下配置。
## Add php module handle
LoadModule php5_module "D:/prg/PHP5/php5apache2_2.dll"
AddType application/x-httpd-php .php
# configure the path to php.ini
PHPIniDir "D:/prg/PHP5"
保存,并重启Apache服务器。注意,路径要跟自己安装路径相对应。PHPIniDir是指配置文件的路径。
从PHP5目录中复制php.ini-recommended到配置文件的路径,并改名为php.ini。打开php.ini,找到extension_dir,将其设置成你ext文件夹所在的路径(ext文件夹在PHP目录内)。找到php_gd2.dll、php_mysql.dll、php_mysqli.dll,去掉前面的注释,重启Apache服务器。如果不出意外,Apache服务器正常启动。写一php文件,名为test.php,内容如下:
<?php phpinfo(); ?>
放到Apache目录下的htdocs。
2.MVC模型简介
模型(Model)代表应用程序的数据(data)和用于控制访问和修改这些数据的业务规则(business rule)。通常模型被用来作为对现实世界中一个处理过程的软件近似。
视图(View)被用来组织模型的内容,它从模型那里获得数据并指定这些数据如何表现。
控制器(Controller)定义了应用程序的行为;它负责对来自视图的用户要求进行解释,并把这些要求映射成相应的行为,这些行为由模型负责实现。
示意图如下:
以上介绍的内容来自J2EE的文档。MVC模型最初是来自SmallTalk社区,后来被引入到Java社区。传统的MVC模型是用于桌面程序的开发。上图说明了,与用户接触的只有视图。用户对视图的操作传递到控制器,控制器经过一系列的业务计算,将数据传到底层的模型层。模型层接受数据后,通知视图更新,这过程是异步的。这里有一个大学时代开发的备忘录,是基于MVC模型开发的,可以点这里下载。显然,对于Web来说,传统的MVC并不太合适,我们无法主动通知视图(HTML,浏览器)进行更新。经过稍作调整后,Web的MVC应该是如下:
3.实现一个控制器:
对于PHP的MVC来说,最重要的是一个控制器。实现一个好的控制器,对于程序扩展有非常好的作用。下面是一个控制器的抽象:
02 | abstract class BaseController |
13 | protected $mStartTime ; |
47 | abstract public function Start(); |
48 | abstract public function doAction(); |
49 | abstract public function End (); |
控制器最重要是三个函数:Start、doAction、End。Start是用作公共部分的处理,例如字符编码、输出的文件格式、Zip压缩等;doAction是根据传递过来action做相应的动作,例如穿过来的action是index,则显示首页。End()则是作一些请求收尾工作和输出处理的内容。为什么要分开这三部分呢?除了逻辑上清晰以外,还可以方便我们以后实现插件机制。如:我们可以再Start之前做一个钩子:before_start,插件注册一个函数到这个钩子,就可以做一些初始化的工作。以下是博客首页控制器的部分代码:
02 | class IndexController extends BaseController |
07 | public function __construct() |
09 | $this ->mEntrance = 'front' ; |
11 | $this ->mrDbo = & new DBO(); |
12 | $this ->mrDbo->Connect(); |
14 | $this ->mrView = & new SmartTemplate(); |
15 | $this ->mrView->template_dir = ( realpath (rootpath. '/tpl/Frontpage/' .blog_template_name. '/' )); |
16 | $this ->mrView->temp_dir = realpath (rootpath. '/temp/' ); |
17 | $this ->mrVIew->cache_dir = realpath (rootpath. '/cache/smarttemplate' ). '/' ; |
19 | $this ->mAction = isset( $_GET [ 'action' ]) ? $_GET [ 'action' ] : 'index' ; |
20 | $this ->mMode = isset( $_GET [ 'mode' ]) ? $_GET [ 'mode' ] : 'normal' ; |
22 | $this ->mPageVar[ 'param' ][ 'action' ] = $this ->mAction; |
23 | $this ->mPageVar[ 'param' ][ 'mode' ] = $this ->mMode; |
25 | $this ->mPageVar[ 'param' ][ 'param1' ] = isset( $_GET [ 'param1' ]) ? $_GET [ 'param1' ] : null; |
26 | $this ->mPageVar[ 'param' ][ 'param2' ] = isset( $_GET [ 'param2' ]) ? $_GET [ 'param2' ] : null; |
27 | //TODO:这里添加一个动态的菜单,让插件能修改首页的菜单项 |
32 | public function Start() |
34 | $this ->mStartTime = microtime(true); |
38 | ob_start( "ob_gzhandler" ); |
44 | if (system_debug) { //如果处于调试模式,则报告所有的错误 |
45 | error_reporting (E_ALL); |
48 | error_reporting (E_ERROR | E_WARNING | E_PARSE); |
50 | date_default_timezone_set(system_timezone); //设置系统默认时区 |
51 | header( 'content-Type: text/html; charset=UTF-8' ); //UTF-8编码 |
56 | public function doAction() |
58 | switch ( $this ->mAction) |
60 | case 'index' : //首页和日志暂时相等 |
68 | $this ->doCommentCommit(); |
77 | $this ->Message( "错误:未实现的action" ); |
86 | $this ->mEndTime = microtime(true); |
87 | $run_time = $this ->mEndTime - $this ->mStartTime; |
89 | $this ->mrView->assign( 'run_time' , $run_time ); |
90 | $this ->mrView->assign( 'query_times' , $this ->mrDbo->GetQueryCount()); |
92 | if (null != $this ->mrView->get_templatefile()) { |
93 | $this ->mrView->output(); |
希望从上面的代码,大家能够更加明白这个控制的工作方式。在这里还想说一下,什么是单入口点。所谓单入口,就是所有程序只能从一个文件中访问。通过不同GET参数实现访问不同页面。这样做的好处是可以限制用户的访问,保证系统的安全。具体实现的方式如下:
1.定义一个入口文件(这里命名为index.php),编写一下代码,定义一个常量:define('rootpath',dirname(__FILE__));//indicate the programme path,this would be use in other php file.
2.再其他的PHP文件中做一下判断:
1 | if (!defined( 'rootpath' )) { //can't direct access this file |
2 | die ( "Access forbidden." ); |
这样就可以限制代码用户对其他页面的访问。下面是一个具体的入口点实现方式,大家可以参照一下:
02 | define( 'rootpath' ,dirname( __FILE__ )); //indicate the programme path,this would be use in other php file. |
03 | //var initialize section |
04 | $entrance = isset( $_GET [ 'go' ]) ? $_GET [ 'go' ] : 'front' ; //get entrance,if can't get any entrance default is index page |
08 | //若控制器较多,调度比较复杂,应该实现一个调度器dispatcher |
13 | case 'front' : //if is a front page,create IndexController |
14 | include_once rootpath. '/includes/core/controller/IndexController.php' ; |
15 | $controller = new IndexController(); |
17 | case 'admin' : //admin,create AdminController |
18 | include_once rootpath. '/includes/core/controller/AdminController.php' ; |
19 | $controller = new AdminController(); |
21 | case 'image' : //course image use different header,so we need a new controller |
22 | include_once rootpath. '/includes/core/controller/ImageController.php' ; |
23 | $controller = new ImageController(); |
25 | default : //not implements controller,print error message |
26 | die ( "未实现的控制器,请求页面失败" ); |
32 | $controller ->doAction(); |
如果你还需要URL路由器等高级功能,也可以在这个文件进行。再次体现的程序的扩展性。
4.视图层
传统的Web程序,视图层都是采用HTML(这里不讲述AJAX等方式的视图)。HTML的渲染,我们可以采用模板引擎。PHP的模板引擎非常的多,著名的有Smarty,更有直接用PHP 作为模板引擎的(例如:国内流行的SaBlog-X)速度的确很快,不过要以复杂性的提高作为代价。我在这里采用的是smarttemplate(目前好像已经改名为QuickSkin)。Smarttemplate的速度非常快,采用缓存编译的方式。一次编译后,结果会被缓存。缓存后的速度和直接适用PHP作为模板引擎的速度相当,是两者折中的一个方案。
具体的使用方法,请参考官网的文档。里面有一些例子,可以让你快速入门。