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