PHP 的Oop+模板编程初级示例与类库下载
2008-10-01 17:18
363 查看
前言: 对PHP,有很多人不赞成用OOP方式编程,反对使用模板者更众,我曾经也是极力排斥,但通过一段时间的尝试之后,发现OOP+模板虽然在速度上慢了可忽略不计的一点时间,编写起来确实爽,尤其表现在业务逻辑的处理与代码的维护性上。 费话少说,下面我就谈谈我的一点学习心得,希望对初学者有所帮助,也希望高手指正。 系统文件存储结构: 先列出树形列表,再解释。 ├─ │ index.php │ ├─sources //子功能模块(业务逻辑)文件目录 │ index.php │ list.php │ details.php │..... │ ├─template //模板文件目录 │ index.tpl │..... │ ├─cache //缓存文件目录 │ gfdgr5123f4sfd9rwfdyt543fdsf12gf.html │..... │ ├─css //CSS 样式表文件目录 │ style.css │ ├─images //图片目录 │ 1.gif │ ..... │ ├─include //包括目录 │ │ config.inc.php //系统全局配置文件 │ │ functions.inc.php //系统全局函数 │ │ │ ├─lib //系统基础类 │ │ Application.inc.php │ │ ..... │ │ │ └─data //数据目录(IP文件) │ ip.dat │ ..... │ ├─js //JS文件目录 │ checkForm.js │ ..... │ ├─admin //后台管理目录 │ │ index.php │ │ │ ├─sources //子功能模块(业务逻辑)文件目录 │ │ index.php │ │ list.php │ │ update.php │ │ ..... │ │ │ └─template //模板文件目录 │ index.tpl │ ..... │ └─tmp //上传临时目录 主目录下的index.php,仅提供转向,转到sources目录下的index.php。同样admin下的index.php转向到admin/sources/index.php。你可以直接用header("location:sources/index.php"),也可以输出一段提示再转向,如:正在进入,请稍候...<script>location.href="sources/index.php"</script> 为什么要这样做呢? sources目录下的index.php是一个统一应用程序接口,通过接收$_GET或$_POST的action参数决定执行相应的子功能模块。例如index.php?action=list,即要执行list.php文件;index.php?action=insert即要执行insert.php文件。这样把应用程序接口index.php和其它子功能模块放在同一级目录,使得业务逻辑更方便;另外sources目录与模板文件目录template在同一级目录,使得模板文件被调用时,其中的图片等外部链接仍然有效,不会出现因目录级别不同找不到图片的现象。 程序设计: 首先,我们有一个统一的应用程序接口sources/index.php。我们看一下index.php的内容: [PHP] <? include (dirname(__FILE__)."/../include/lib/Application.inc.php"); $app = new Application(); $app->setRoot(dirname(__FILE__)) ; $app->setDefaultAction("main"); $app->run(); ?> [/PHP] 上面的代码很简单: 第1行:载入应用程序接口类Application.inc.php。有很多朋友使用include和require时,在多级调用后经常出现找不到文件的问题,如果象上面那样:绝对路径+相对路径,包你永远正确。扯远了。。。^_^ 第4行:$app->setRoot(dirname(__FILE__)) ;设置子功能模块根目录。由于index.php与子功能模块文件在同一目录,因此设为dirname(__FILE__)。 第5行:$app->setDefaultAction("main");设置默认子功能模块,即没有$_GET['action']和$_POST['action']时执行main.php。 很重要的在第六行$app->run(),开始执行子功能模块。 下面就来看下Application.inc.php中run()是如何运作: 代码如下: [PHP] <? function run() { $action = $this->getAction(); $page_class_file = $this->root . $action . '.php'; include_once($page_class_file); $page = & new CPage($this); $page->execute(); exit (); } ?> [/PHP] 首先我们通过getAction()得到参数action的值, 比如list,当前路径+list+.php就是将要执行的子模块 include_once($page_class_file); 载入list.php 很显然,在list.php中有一个类CPage ,并有一个方法函数execute()作为接口来处理数据并显示该页。 在初始化CPage类时,我们将$app对象用$this作为参数传给了CPage,那么在CPage中就可以使用$app对象中封装的所有方法。因此我们可以在$app中封装多一些的常用方法。比如,可以将数据库的初始化,模板的初始化封装进去。 完整代码如下: Application.inc.php [PHP] <?php if(!defined("__CLASS_APPLICATION__")) { define("__CLASS_APPLICATION__",1); require(dirname(__FILE__)."/PhpClass.inc.php"); class Application extends PhpClass { var $db = null; var $defaultAction ; var $root; //构造函数 function Application($root='') { if (!defined(ACTIONSTR))define("ACTIONSTR","action"); if (!empty($root))$this->setRoot($root); } //设置子功能模块所在的根目录 function setRoot($root='') { if (empty($root))$root = dirname($_SERVER['SCRIPT_FILENAME']); if (!is_dir($root)) return $this->catchErr("无效的路径"); if ( substr($root,-1) != DIRECTORY_SEPARATOR) $root .= DIRECTORY_SEPARATOR; $this->root = $root; } //设置默认要执行的功能页 function setDefaultAction($name) { $this->defaultAction = $name; } //执行子功能页 function run() { $action = $this->getAction(); $page_class_file = $this->root . $action . '.php'; include_once($page_class_file); $page = & new CPage($this); $page->execute(); exit (); } //获取参数action的值 function getAction() { $_name = (isset($_POST[ACTIONSTR])) ? $_POST[ACTIONSTR] : $_GET[ACTIONSTR]; if (empty($_name)) $_name = $this->defaultAction; return $_name; } //模板 function tpl($templateDir='') { $this->includeClass('Vant'); if (empty($templateDir)) $templateDir = $this->root . 'templates/' $tpl = & new Vant($templateDir); return $tpl; } //载入类文件 function includeClass ($fileName, $path = '', $lastName = '.inc.php') { if ( substr($path,0,1) != DIRECTORY_SEPARATOR) $path = DIRECTORY_SEPARATOR . $path; if ( substr($path,0,-1) != DIRECTORY_SEPARATOR) $path .= DIRECTORY_SEPARATOR; if (empty($fileName) ) return $this->catchErr("无效的class名"); include(dirname(__FILE__) . $path . $fileName . $lastName); } //数据库连接 function connectDb($host='',$username='',$password='',$database='') { $this->includeClass('DB'); $db = new DB($host,$username,password,database); $db->connect(); $this->db = & $db; return $db; } } //end class }//end if defined ?> [/PHP] 作者: lwg888 发布日期: 2004-7-02 上面的代码中有一个方法includeClass(),专门用来包含类与函数等文件,注意,请不要用它来包含配置文件、普通PHP文件等。 Application类还继承了PhpClass类。PhpClass类里面是些什么东些呢?在我所有的类库中,基本上每个类中都要用到一些相同的方法与属性,比如错处理catchErr()等,将它们封装起来,作为所有类的祖类。 PhpClass的完整代码如下: PhpClass.inc.php [PHP] <?php if(!defined("__CLASS_PHPCLASS__")) { define("__CLASS_PHPCLASS__",1); class PhpClass{ var $debug = false; //是否显示调式信息 var $debugMsg = ''; //记录调式信息 var $errMsg = ''; //记录第一次的错误信息 var $error_report = true; //是否输出错误信息 var $error_halt = true; //出错后是否停止执行 //为成员变量赋值 function setVal($name,$value) { $this->$name = $value; } //取得成员变量的值 function getVal($name) { return $this->$name; } //捕获错误 function catchErr($msg) { if(empty($this->errMsg)) $this->errMsg = $msg; if ($this->error_report) echo $this->errMsg; if ($this->error_halt) exit; return false; } //输出错误 function err($exit = false) { if (!empty($this->errMsg)) { echo $this->errMsg; if ($exit) exit; } } }// end class }// end if defined ?> [/PHP] 下面我们回到list.php中去,看子功能模块如何运作 从前面的介绍我们知道了list.php,必有一个类CPage且其中必定有两个函数: 一个构造函数CPage(),一个execute(); 通过构造函数的参数将$app对象接收到,那么简单代码如下: [PHP] list.php <?php class CPage { function CPage(& $app) //$app就是Application对象的实例 { } function execute() { } } ?> [/PHP] 由于很多子功能模块可能要完成一些共同的功能,如显示logo,copyright等,我们可以将这样共同的功能封装在一个类中,命名为Page类,作为所有子功能模块的父类,所有子功能模块都从它继承。 看一下Page.inc.php: [PHP] <? class Page { var $app; var $vars=array(); function Page(&$app) { $this->app = & $app; } function setCopyRight() { $this->vars['copyright'] = "CopyRightwg888"; } } ?> [/PHP] list.php中的CPage类就从Page类继承 代码示例: [PHP] <?php include("Page.inc.php"); class CPage extends Page { var $pt; var $app; function CPage(& $app) { $this->age($app); } function execute() { $db = $this->app->connectDb(); //利用Application对象中的数据库连接方法 $sql= "select * from table ..."; $this->app->includeClass ('PageTurn'); //载入PageTurn.inc.php翻页类文件 $pt = & new PageTurn(20); //初始化翻页类,每页显示20条 $pt->query($sql,$db->conn); //执行SQL语句 $this->pt = & $pt; $this->show(); //显示网页 } function show() { $tpl=$this->app->tpl(); //建立模板对象 $tpl->set("loop",$this->pt->field); $tpl->set("copyright",$this->vars['copyright']); //Page类中的 $vars['copyright'] echo $tpl->parse('list.tpl'); //显示模板 } } ?> [/PHP] 上面用到了分页类PageTurn与模板类Vant,大家可以参考下载中的相关类 讲了这么多,我们已经基本上弄清了用OOP+模板方式写程式的方法,下面就来总结它的好与歹。 如果你不喜欢用OOP方式编程,你可以说:类=累。我同意,但不以OOP方式编程,运行速度是会快一些,而你会变的很累,不管是业务逻辑的组织还是今后代码的维护,都不是一件轻松的事。在机器性能日益提高和网络宽频日益普及的今天,速度不是单方面追求的目标,我们要在速度与代码易用性、易编写性之间取得平衡。 从上面的讲解我们可以看出:完全实现了Model模型/逻辑、View视图/界面、Controller控制/流程 的分离。使得结构非常清晰,维护非常方便,模型设计者,界面设计者与流程控制设计者能更好的分工与合作。代码可重用,今后如果要开发一个新的项目,很快就能完成,因为你可能只需叫美工重新设计一下模板,或者稍稍修改一下子功能模块。 还有一点不得不提: index.php是一个统一应用程序接口,通过$_GRT['action']或$_POST['action'],决定执行哪个子功能模块。当它执行该模块时是将它include进来,因此所有的操作都是在index.php中进行,所呈现的网页都是index.php?action=...,这样使我们控制流程非常方便。比如要显示用户列表,只需调用list.tpl模板,要显示错误信息,只需调用errmsg.tpl模板,甚至不必要使用header("location:..")来转向,不管是显示用户列表还是显示错误信息,所有的$_GRT或$_POST或其它变量都还在,不用象转向时那样用?xx=...传一大堆变量过去,不是有不少人常问“数组能不能传递?”“对象能不能传递?”, 写到这里,一点劣见,望大家指正 。
相关文章推荐
- PHP面向对象(OOP)编程入门教程
- php实现下载限制速度示例分享
- PHP实现的文件操作类及文件下载功能示例
- PHP将服务器上的文件下载(例如下载Excel模板)
- 【PHP面向对象(OOP)编程入门教程】2.什么是类,什么是对象,类和对象之间的关系
- 使用PHP强制下载PDF文件示例
- PHP面向对象(OOP)编程完全教程
- php Http_Template_IT类库进行模板替换
- PHP 面向对象程序设计(oop)学习笔记(一) - 抽象类、对象接口、instanceof 和契约式编程
- php实现下载限制速度示例分享
- 跟着百度学PHP[4]OOP面对对象编程-15-魔术方法__call方法
- PHP面向对象(OOP)编程入门教程链接
- 基于PHP的短信接口调用示例代码模板
- PHP编程求最大公约数与最小公倍数的方法示例
- php中钩子(hook)的应用示例演示与下载
- php应该遵循什么样的编码规范?PHP符合PSR编程规范示例
- 跟着百度学PHP[4]-OOP面对对象编程-2-属性和方法
- 跟着百度学PHP[4]OOP面对对象编程-5-内部引用$this
- php下载模板js操作
- 【PHP面向对象(OOP)编程入门教程】10.__set(),__get(),__isset(),__unset()四个方法的应用