最近在一家公司实习.老板让学PHP,最初学脚本语言时,ASP,JSP,PHP其实我都有在书店翻过书. ASP:词法元素很清晰(我指的是<%%>这一对). JSP:一看哪书老厚!框框也比较多,什么j2se,j2ee,j2me不说,还有好多什么接口和类什么的,什么工具箱,好像学这个要学好多东东,看着就头大,这到哪天能搞懂这些东东. PHP:我相信大家都有我这样的感觉:好多看着别扭的符号.N多函数. 最后就选了ASP.
下面进入正题,以一个PHP示例来和大家一起谈讨WEB开发错误调试.为什么要以PHP为例呢,因为这个符号具多,最容易出错.大家在写代码时难免有笔误和思绪不好理的情况,这时敲的代码就容易给你500错误和白脸. 主题: 1.过程化函数或类的封装 2.多敲点打印输出(示例中函数名最后是"info"的) 3.尽可能的把您的意图理清 4.测试驱动开发(Java有本测试驱动开发的书,说一点个人心得)
A:过程化函数或类的封装 如果您不会以ASP,PHP,JavaScript类的方式开发,过程化一定要多练.以一个大家都会遇到的需求说起: sign用户登录 1.一个表单HTML页面,获取用户输入的信息. 2.一个ASP,PHP页接到参数,经过加工处理:过滤非法用户(root,admin,正则表达式匹配). 3.把格式正确的数据送到服务器验证页:看用户是否注册过和用户和密码是否正确 4.如果数据存在该用户则跳转到下个页面或提示成功消息的页面,反之就跳转到登录页或错误提示页.
以上四步还可以细分,我写过以上流程最多的时候有5个ASP页面.为什么一页能搞定的要写这么多页呢? 1>:团队开发有利于分工 2>:一个人在一个页面中(或一个流程中)敲的代码越多越容易出错. 3>:容易查找到错误 4>:最能体现过程化语言的优势.一块干一个事情.容易分解难度.有利用重用和封装.
经常在论坛中看到好多人贴代码一贴N长!让想帮您的人都心里犯醋.分解以后您只要贴出错的部分,让人一看就大体能理解这一个块要干什么.这样您发现错误时也容易排错.
C:尽可能的把您的意图理清 其实您只要懂了基本语法或只有半懂应该写出一手好代码也不是难事.关键是:作的案例不够多;没有完全理解业务流程;对所需考虑的外在因素估计错误. 这样的状态开发下去就成了一团糊糊.出现一个错误就修补一个错误.个人认为没有最自然的方案就出去走走清清头脑或去参考一下别人写的类似的案例
D:测试驱动开发 我们正常都是先开发再测试.这样就形成是跟据现有代码去测试.根本没法应对应用的变化性.记用户去适应您的代码.根据您的代码去说服用户.这是大错特错的. 良构的应用是根据需求开发.跟着用户的意愿走.用满足用户意图的产品换来长久的合作.(产品的生存周期).在编码价段根据测试用力写代码.保证代码的清洁性. 一条多余的代码没用,这样才能体现代码的力与美.总结一句:一条能完成的不要写两条.一般业务函数或业务方法不要超过12行,在1-6行为最佳.
B:多敲点打印输出 以下是输出一个白屏的PHP代码.一个数据库连接类.一个分页类.一个调用页面.最开始是500错误.我调好后还原了.我注释的部分有助于你在排错时划分错误的界限.不至于一下头大. 排错时只要按代码的流程一条一条看下去加上一点打印输出足让你在很短的时间修复错误.如果您以上三点都没作到您修复错误的时间将以直线增长.
username=$strUser; $this->password=$strPassword; $this->locationLink=$strLocation; $this->dbname=$strDB; } public function getConnection(){ $this->currentConn=mysql_connect($this->locationLink,$this->username,$this->password) or die ("Query failed: ".mysql_error()); mysql_query("SET CHARACTER SET 'GB2312'",$this->currentConn); mysql_select_db($this->dbname) or die('Could not select database'); return $this->currentConn; } public function setConnectionTerminater(){ mysql_close($this->currentConn); } public function getConnectionInfo(){ printf("net user name: %s./n ",$this->username); printf("net user passowrd: %s./n ",$this->password); printf("net server position: %s./n ",$this->locationLink); printf("net database name: %s./n ",$this->dbname); } } ?>
pageRecords=$strPageSize; $this->currentPage=$strCurrentPage; $this->tSQL=$strSQL; if(is_object($strConn)){ $this->currentConn=$strConn; } } public function getTotalRecords(){ $result=mysql_query($this->tSQL); if(($tempCount=mysql_num_rows($result))>0){ return $this->totalRecords=$tempCount; }else{ exit; } } public function getTotalPages(){ if($this->getTotalRecords() % $this->pageRecords ==0){ $this->totalPages=$this->getTotalRecords() / $this->pageRecords; }else{ $this->totalPages=intval($this->getTotalRecords() / $this->pageRecords +1); } return $this->totalPages; } public function getCurrentPage(){ if($this->currentPage <= 1){ $this->currentPage = 1; } if($this->currentPage >= $this->getTotalPages()){ $this->currentPage = $this->getTotalPages(); } if(is_null($this->currentPage)){ $this->currentPage= 1; } return $this->currentPage; } public function getRecordSet(){ $strStart=($this->getCurrentPage() -1) * $this->pageRecords; $strEnd=$this->getCurrentPage() * $this->pageRecords; $tempResult=mysql_query($this->tSQL); $returnArray=array(); if(mysql_data_seek($tempResult,$strStart)){ //结果集内部指针是否有移动 print_r("T"); for($i=$strStart;$i<$strEnd;$i++){ $tempRow=mysql_fetch_object($tempResult); $returnArray->push($returnArray,$tempRow); //结果是否正常装入结果数组 print_r($returnArray); } } return $returnArray; } public function getCurrentPageInfo(){ printf("page size length: %d./n ",$this->pageRecords); printf("current page function number: %d./n ",$this->getCurrentPage()); printf("record number: %d./n ",$this->getTotalRecords()); printf("count page number: %d./n ",$this->getTotalPages()); } } ?>
getConnection(); //测试连接类是否工作 print($conn->getConnectionInfo()); $tSQL="SELECT name,price FROM book"; $tPage=new CurrentPage($MySQLConnection,$tSQL,$definePageSize,$currentPage); //测试分页类是否正常初始化 print($tPage->getCurrentPageInfo()); $recordSet=tPage->getRecordSet(); //校验类的完整性 print($tPage->getCurrentPageInfo()); for($i=0;$iname." "; print $recordSet[$i]->price." "; } }catch(Exception $e){ $e->getMessage(); } $conn->setConnectionTerminater(); ?>
1>://测试连接类是否工作 如果屏幕上没有输出连接类的getConnectionInfo()函数.说明在连接类里就有错误
2>://测试分页类是否正常初始化 原理同上面一样!因为这两个打印输出只证明这两个类是否正常初始化.类里的属性值是否正确
3>://结果集内部指针是否有移动 现在已经步入了业务流程了!请确定外在因素是非有错误.前几天我就犯了这样的错误.代码怎么看都没有错.由于是从SQL Server中读取数据再写到MySQL中.5个小时后才发数据库的类型是ntext没法直接转到MySQL中.
4>://结果是否正常装入结果数组 如果屏幕还没到数组的输出,或者输出了非期望的结果:表明您的循环出错了.如果前后输出不一致,因为类里会打印一遍,调用页还会打印一遍.
总结: 能写一切代码并没有什么了不起!只证明您从业多年,思维丰富.但能修复一切错误的您一定比能写一切代码的人能力要强的多. 祝大家在开发中修复错误能一帆风顺