首页 » PHP和MySQL Web开发(原书第4版) » PHP和MySQL Web开发(原书第4版)全文在线阅读

《PHP和MySQL Web开发(原书第4版)》7.4 Bob的汽车零部件商店应用程序的异常

关灯直达底部

在第2章中,我们介绍了如何以普通文件的格式保存Bob汽车零部件商店的订单数据。我们知道,文件I/O(事实上,任何类型的I/O)是程序经常出现错误的地方。这就使得它成为应用异常处理的合理位置。

回顾初始代码,可以看到,写文件时可能会出现三种情况的错误:文件无法打开、无法获得写锁或者文件无法写入。我们为每一种可能性都创建了一个异常类。这些异常类的代码如程序清单7-4所示。

程序清单7-4 file_exceptions.php——文件I/O相关的异常

<?php

class fileOpenException extends Exception

{

function__toString

{

return/"fileOpenException/".$this->getCode

./":/".$this->getMessage./"<br/>/"./"in/"

.$this->getFile./"on line/".$this->getLine

./"<br/>/";

}

}

class fileWriteException extends Exception

{

function__toString

{

return/"fileWriteException/".$this->getCode

./":/".$this->getMessage./"<br/>/"./"in/"

.$this->getFile./"on line/".$this->getLine

./"<br/>/";

}

}

class fileLockException extends Exception

{

function__toString

{

return/"fileLockException/".$this->getCode

./":/".$this->getMessage./"<br/>/"./"in/"

.$this->getFile./"on line/".$this->getLine

./"<br/>/";

}

}

?>

Exception类的这些子类并没有执行任何特别的操作。事实上,对于这个应用程序的作用来说,可以让它们成为空的子类或者使用PHP所提供的Exception类。然而,我们为每一个子类提供了_toString方法,从而可以解释所发生的异常类型。

我们重新编写了第2章的processorder.php文件,在其中使用了异常。该文件的新版本如程序清单7-5所示。

程序清单7-5 processorder.php——Bob汽车零部件商店程序的订单处理脚本,该脚本已经包括了异常处理

<?php

require_once(/"file_exceptions.php/");

//create short variable names

$tireqty=$_POST[/'tireqty/'];

$oilqty=$_POST[/'oilqty/'];

$sparkqty=$_POST[/'sparkqty/'];

$address=$_POST[/'address/'];

$DOCUMENT_ROOT=$_SERVER[/'DOCUMENT_ROOT/'];

?>

<html>

<head>

<title>Bob/'s Auto Parts-Order Results</title>

</head>

<body>

<h1>Bob/'s Auto Parts</h1>

<h2>Order Results</h2>

<?php

$date=date(/'H:i,jS F/');

echo/"<p>Order processed at/".$date./"</p>/";

echo/'<p>Your order is as follows:</p>/';

$totalqty=0;

$totalqty=$tireqty+$oilqty+$sparkqty;

echo/"Items ordered:/".$totalqty./"<br/>/";

if($totalqty==0){

echo/"You did not order anything on the previous page!<br/>/";

}else{

if($tireqty>0){

echo$tireqty./"tires<br/>/";

}

if($oilqty>0){

echo$oilqty./"bottles of oil<br/>/";

}

if($sparkqty>0){

echo$sparkqty./"spark plugs<br/>/";

}

}

$totalamount=0.00;

define(/'TIREPRICE/',100);

define(/'OILPRICE/',10);

define(/'SPARKPRICE/',4);

$totalamount=$tireqty*TIREPRICE

+$oilqty*OILPRICE

+$sparkqty*SPARKPRICE;

$totalamount=number_format($totalamount,2,/'./',/'/');

echo/"<p>Total of order is/".$totalamount./"</p>/";

echo/"<p>Address to ship to is/".$address./"</p>/";

$outputstring=$date./"t/".$tireqty./"tirest/".$oilqty./"oilt/"

.$sparkqty./"spark plugst$/".$totalamount

./"t/".$address./"n/";

//open file for appending

try

{

if(!([email protected](/"$DOCUMENT_ROOT/../orders/orders.txt/",/'ab/')))

throw new fileOpenException;

if(!flock($fp,LOCK_EX))

throw new fileLockException;

if(!fwrite($fp,$outputstring,strlen($outputstring)))

throw new fileWriteException;

flock($fp,LOCK_UN);

fclose($fp);

echo/"<p>Order written.</p>/";

}

catch(fileOpenException$foe)

{

echo/"<p><strong>Orders file could not be opened.

Please contact our webmaster for help.</strong></p>/";

}

catch(Exception$e)

{

echo/"<p><strong>Your order could not be processed at this time.

Please try again later.</strong></p>/";

}

?>

</body>

</html>

可以看到,以上脚本的文件I/O部分被封装在一个try代码块中。通常,良好的编码习惯要求try代码块的代码量较少,并且在代码块的结束处捕获相关异常。这使得异常处理代码更容易编写和维护,因为可以看到所处理的内容。

如果无法打开文件,将抛出一个fileOpenException异常;如果无法锁定该文件,将抛出一个fileLockException异常;而如果无法写这个文件,将抛出一个fileWriteException异常。

分析catch代码块。要说明这一点,我们只给出了两个catch代码块:一个用来处理fileOpen-Exception异常,而另一个用来处理Exception。由于其他异常都是从Exception继承过来的,它们将被第二个catch代码块捕获。catch代码块与每一个instanceof操作符相匹配。这就是为每一个类扩展自己异常类的理由。

一个重要警告:如果异常没有匹配的catch语句块,PHP将报告一个致命错误。