|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
怎么样出来了吧,怎么样自己也可以写出php程序了,虽然离职业和专业的人还有很远,但是好的开始是成功的一半。这个时候改怎么做了呢。现在就是拿1本高手推荐的书,重头到尾读1遍,我说的这个读是自己看。毛病|毛病处置 PEAR供应了壮大的毛病处置机制。这篇文章向你展现若何从这个体系中获益。
很多法式已利用了PEAR的包。很多PHP法式员或多或少的熟习了PEAR中的毛病处置。然而这个机制其实不局限于PEAR的包――一切人都能在他们的类和法式中利用这些办法。
这篇文章被分为两个局部:起首咱们将看看类顶用于毛病处置的函数,然后咱们将看看若何基于PEAR毛病处置机制来处置毛病。
咱们的例子类称为cvs2db,它把数据从CSV文件拔出到数据库的表中。由于数据多是手写的,他们的数据应当在拔出之前先失掉验证――落实postcode。函数import()完成读入,反省和拔出的任务;它前往破坏的纪录数量。假如前往的值大于0,失足的纪录集可以利用exportUnvalid()写入到新的CSV文件中。典范的用法是如许的:
<?php
$cd = new csv2db();
$dsn = 'mysql://root@localhost/csv2db';
if( 0 < $cd->import("./dat.csv", $dsn, 'address')) {
$cd->exportUnvalid("./dat2.csv");
}
?>
能够的毛病包含:
要导入的CSV文件不存在,
毗连到数据库掉败,
纪录集破坏,和CSV导出文件没法创立。
在供应毛病信息的经典处理计划中你能够写如许的代码:
<?php
$cd = new csv2db();
$dsn = 'mysql://root@localhost/csv2db';
$result = $cd->import("./dat.csv", $dsn, 'address')
switch($result) {
case FILE_NOT_OPENED:
...
break;
case DATABASE_ERROR:
...
break;
default:
if(0 < $result) {
$cd->exportUnvalid("./dat2.csv");
} else {
echo 'every thing ok!'
}
}
?>
这关于短的剧本来讲是可承受的也是经常使用的举措――然而关于毛病处置常常遭到存眷的大法式来讲不是如许。传统的能够性强制类的作者做终究的决意!在大局部情形下,这个决意依据的是那时对类的挪用而不是基于临时的利用和可重用代码的思惟。一个天真的毛病处置机制是可重用代码的主要局部,PEAR Error API 就是如许的一种遭到优秀测试的机制。
用户眼中的类
除那两个函数以外,类供应了一套毛病处置函数和一个本人的毛病对象称为DB2CVS_Error,它有一个特别的当地化的毛病信息的特征功效。
如今我将向你展现若何在毛病产生时掌握类的行动。
部分和全局毛病处置
你用setErrorHandling()办理毛病处置;这个函数需求两个参数:第一个是毛病形式,而第二个(可选的)参数是毛病形式特定的选项。例如 setErrorHandling(PEAR_ERROR_PRINT, 'This error occurred %s') 还有 setErrorHandling(PEAR_ERROR_TRIGGER, E_USER_WARNING)。
这个函数的挪用体例是普通行动中最主要的:静态仍是实体。在类cvs2db中,咱们能二者都用来设置毛病处置,一切这些挪用有不异的布局――为类设置毛病形式:
// per instance
$cd = new csv2db();
$cd->setErrorHandling(PEAR_ERROR_DIE):
// static
CVS2DB::setErrorHandling(PEAR_ERROR_DIE);
PEAR::setErrorHandling(PEAR_ERROR_DIE);
假如二者给出一样的了局,区分在哪?实体挪用仅仅为谁人类设置而静态挪用关于一切利用PEAR_Error或从谁人类派生的一切类起感化。这个也感化于第一个静态号令CVS2DB::setErrorHandling(PEAR_ERROR_DIE)――固然它看上去仅仅影响了cvs2db类。
总结:作为一个实体函数利用号令意味着仅仅为这个实体(部分)设置毛病形式,而作为静态函数来挪用就是为全部剧本设置毛病形式(全局)。
setErrorHandling() 和 raiseError()
两个函数都可以被静态挪用和作为实体的函数挪用。记住如何的一个组合使得他们若何相互影响的很主要。
根基上是:setErrorHandling()的静态挪用仅仅影响raiseError()的静态挪用――setErrorHandling()作为实体函数仅仅影响raiseError()作为静态函数挪用。在类csv2db中,利用csv2db::setErrorHandling()来设置毛病形式是不成行的,由于咱们利用$this->raiseError(...)。处理这个闻天有一点小技能――改写raiseError():
function raiseError(...,$mode=null, $options=null,...) {
if($mode==null && $this->_default_error_mode!=null) {
$mode = $this->_default_error_mode;
$options = $this->_default_error_options;
}
return PEAR::raiseError(...,$mode, $options,...);
}
如许,咱们映照实体挪用到静态上,假如你用毛病形式挪用raiseError(),然后这个形式将会掩盖这些设置――这里是指的是全局的设置。
你应该小心毛病是若何被类抛出的,假如你不当心,这能够招致不成预期的反作用。
毛病的形式
对毛病形式的懂得关于利用PEAR的毛病处置来讲是主要的。PEAR毛病处置让用户可以决意怎样去做――注重:下文中术语用户指的的是实践利用PEAR_Error法式的开辟者而不是阅读剧本了局或网页的用户。我将具体展现能够的毛病形式。
PEAR_ERROR_DIE――将这个形式开启,法式将终结而且将打印毛病信息。可选的,你能界说一个printf()式的字符串,它可以用于发生信息;起首'%s'在字符串中将替换贮存在毛病对象中的毛病信息。
PEAR_ERROR_PRINT――仅仅打印毛病信息,包含用于PEAR_ERROR_DIE的一样的可选用的字符串。
PEAR_ERROR_RETURN――当毛病产生时的普通行动;你能用类供应isError()函数或PEAR::isError()反省毛病。
$db->setErrorhandling(PEAR_ERROR_RETURN)
if(!csv2db::isError(0 < $d = $cd->import("./dat.csv", $dsn, 'address'))) {
if(!csv2db::isError($cd->exportUnvalid("./dat2.csv")) {
} else {
// handle error
}
} else {
// handle error
}
PEAR_ERROR_TRIGGER――这儿函数向PHP运转时毛病行动一样。你必需界说哪一种毛病应当产生:E_USER_NOTICE,E_USER_WARNING或E_USER_ERROR。他们直接和PHP自己发生的信息绝对应。请注重,在毛病信息中毛病产生的那行(xxx on line yy)指的是在PEAR.php中挪用trigger_error的那行――而不是毛病直接产生的那行。
PEAR_ERROR_CALLBACK――这是只在一个中央处置毛病而且让你得代码不必思索毛病处置的最好体例。它需求一个函数或类函数来捕捉毛病,你能写一个listing 2中展现的那样的剧本,个中可以看到类相干毛病对象的优点:import()函数抛出一个CSV2DB_Error给基于CSV的毛病和一个DB_Error对象给相干于数据库会见的毛病。
Listing 2
$cd = new csv2db();
$cd->setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
$dsn = 'mysql://root@localhost/csv2db';
if( 0 < $d = $cd->import("./dat.csv", $dsn, 'address')) {
$cd->exportUnvalid("./dat2.csv");
}
function handleError($error) {
if(DB::isError($error) {
// handle database error
}
if(csv2db::isError($error) {
switch($error->getCode()) {
case FILE_NOT_OPENED :
...
break;
case CORRUPTED_RECORD :
...
break;
}
}
}
单个的毛病处置
咱们有两种能够的毛病:咱们可以疏忽的毛病(破坏的纪录),和使得法式没法运转的毛病(找不到文件或打不开数据库)。假如你在shell剧本中利用类,你可让剧本终止于第二类毛病。
天然的,你可以写 $cd->setErrorHandling(PEAR_ERROR_DIE)――然而这能够在假如破坏的纪录毛病产生时招致成绩。在如许的情形下你需求对某个毛病停用或交换毛病处置举措的能够。处理举措时expectError(),假如你传递一个毛病代码给这个函数,指定毛病的毛病形式将被独自于缺省毛病形式地设置为PEAR_ERROR_RETURN。
expectError()函数把传递来的毛病代码贮存在栈中,利用popExpected()移出最初传递的毛病代码。自从PHP 4.3以后你还能利用delExpect()了;这个函数从栈中删除指定毛病代码的婚配,你不需求关怀地位了。
在实践利用中,是如许的:
$cd->setErrorHandling(PEAR_ERROR_DIE);
...
$cd->expectError(CORRUPTED_RECORD);
$cd->import(...);
$cd->popExpect();
pushErrorHandling() 和 popErrorHandling() 用起来差不多;他们可以临时的掌握毛病处置。例如:假如在 exportUnvalid() 中的文件不克不及翻开,你想要疏忽毛病:
PEAR::pushErrorHandling(PEAR_ERROR_RETURN);
$cd->exportUnvalid("./dat2.csv");
PEAR::popErrorHandling();
注重挪用办法的区分!expectError()/popExpect()必需作为实体函数来挪用――pushErrorHandling和popErrorHandling可以静态挪用。假如作为实体函数,那末他们仅仅影响谁人实体。
用户有良多能够性,这是不是又意味着法式员要做良多的任务呢?是,是由于你要比return false做更多的工作;否,是由于PEAR Error API给你完成了良多任务。
一些关于毛病处置的思虑
作为好的法式员,你不该该从你的类的用户眼中讳饰起切实的毛病缘由。这禁止了复杂的return false的用法;还要注重也能够被PHP主动型别转换为0――这关于import()函数来讲意味着一切的纪录都已被准确拔出了!复杂地终止剧本?,能够关于复杂地PHP shell剧本来讲这是可以承受地,然而关于一个web法式来讲是一个坏的选择!并且,在纪录破坏的情形,毛病是可以被疏忽的。甚么不trigger_error()?这是一个能够的选择,然而有两个弱点:类的行动取决于php.ini的设置,并且关于类来讲这类行动不罕见。能够功能够需求用额定的函数找失足误形态。即便是一切类都供应了非尺度的函数名,这仍是有成绩的,并且类的用户看上去会健忘那样的函数挪用――正如邮件列表和旧事组中显示的那样。怎样办?让用户决意PEAR毛病处置API。PEAR毛病体系被普遍晓得而且很多类已利用了PEAR类;因此咱们不管若何必需用PEAR毛病处置机制――为何不创立在其上呢?这防止了后面提到的成绩而且给用户供应了很大的能够性。看看Listing 1,它展现了csv2db类和它的毛病对象的完成。它多是有些让人吓到,然而咱们将一行行地阅读源代码。
Listing 1
<?php
require_once 'PEAR.php';
require_once 'DB.php';
define("FILE_NOT_OPENED", 10);
define("CORRUPTED_RECORD", 20);
class csv2db extends PEAR{
var $records=array();
var $unvalid=array();
function csv2db() {
$this->PEAR("CSV2DB_Error");
}
function import($file, $dsn, $table) {
$this->PEAR("CSV2DB_Error");
if($fp=@fopen($file, 'r')) {
while($data=fgetcsv($fp, 1024,';')) {
$this->records[]=$data;
}
fclose($fp);
} else {
return $this->raiseError(null, FILE_NOT_OPENED);
}
$unvalidCount=0;
$storeMode = $GLOBALS['_PEAR_default_error_mode'];
$storeOpts = $GLOBALS['_PEAR_default_error_options'];
$GLOBALS['_PEAR_default_error_mode'] = $this->_default_error_mode;
$GLOBALS['_PEAR_default_error_options'] = $this->_default_error_options;
$db = DB::connect($dsn);
$GLOBALS['_PEAR_default_error_mode']= $storeMode;
$GLOBALS['_PEAR_default_error_options'] = $storeOpts;
if(!DB::isError($db)) {
$db->setErrorHandling($this->_default_error_mode,
$this->_default_error_options);
$qp = $db->prepare("INSERT INTO $table VALUES (?, ?, ?, ?)");
foreach( $this->records as $record) {
if(preg_match('/d{5}/',$record[2])) {
$db->execute($qp, $record);
} else {
$unvalidCount++;
$this->unvalid[]=$record;
$this->raiseError(corrupted record, CORRUPTED_RECORD);
}
}
$db->disconnect();
} else {
return $db;
}
return $unvalidCount;
}
function exportUnvalid($file) {
if($fp=@fopen($file, "w")) {
foreach($this->unvalid as $data) {
fwrite($fp, implode(';', $data)."n", 1024);
}
fclose($fp);
} else {
return $this->raiseError(null,FILE_NOT_OPENED);
}
}
function isError($data) {
return (bool)(is_object($data) &&
(get_class($data) == 'CSV2DB_Error' ||
is_subclass_of($data, 'CSV2DB_Error')));
}
}
class CSV2DB_Error extends PEAR_Error {
var $msgs = array(
FILE_NOT_OPENED =>
array( 'de' =>"Datei konnte nicht ge?ffnet werden",
'en' => "File couldn't be opened"),
CORRUPTED_RECORD =>
array( 'de' =>"fehlerhafter Datensatz",
'en' => "corrupted record")
);
function CSV2DB_Error($message=null, $code = null, $mode = null,
$level = null, $debuginfo = null) {
$this->PEAR_Error(null, $code, $mode, $level, $debuginfo);
}
function getMessage($lang = "en") {
return $this->msgs[$this->code][$lang];
}
}
?>
本人的毛病对象
有一个本人的毛病类老是好的,固然它能够关于这么一个小的类来讲是太大的额定承当――然而这个类仅仅是一个例子而且你从假如没有毛病对象需求良多代码来完成的特征那儿获益很多。优点是:起首毛病是直接赋给类的;和当地化变得加倍轻易。
类必需从PEAR_Error承继而来,为的是坚持咱们的完成复杂,不然PEAR::isError()将不克不及正常任务。
完成包括了机关函数,个中没有改动地把参数传递给了PEAR_Error地机关函数。
改写getMessage()函数是供应当地化毛病信息地关头。毛病定西被界说为类的变量而且将取决于言语静态的赋值。这也将匡助动静会萃于一处――而不是把他们分离于全部次要类的源代码中。
完成PEAR毛病处置
你在文章的第一局部看到了咱们的类供应了一堆函数――然而他们中的仅唯一四个是直接完成的。一切的相干函数的毛病处置是由PEAR基类供应的。为了从一切那些毛病处置特征中获益,咱们必需让cvs2db类从PEAR基类承继,也就是:class csv2db extends PEAR。
在后面的毛病对象段落中,我从对isError()的注释入手下手。掩盖这个办法不是需要的,固然它的确使得咱们可以直接反省咱们的毛病类,而且使得毛病跟踪加倍准确而且能够勤俭了几毫秒。
类的机关函数仅仅只是用毛病类称号最为参数挪用了父类的机关函数。这个挪用注册了咱们的毛病对象而且确保了咱们的毛病类在每次触发毛病的时分被利用。
raiseError
在import()和exportUnvalid()的函数体中对raiseError()的利用是值得注重的。这是创立毛病的关头函数;PEAR供应两个函数用于这个目标:raiseError() 和 throwError()。后一个自从PHP 4.3入手下手存活在而且是raiseError()的一个简化变体,二者行动是分歧的;它们的参数在段落 'raiseError 和 throwError' 中描写。
raiseError 和 throwError
原型:
&raiseError( $message, $code, $mode, $options, $userinfo, $errorclass, $skipmessage)
&throwError( $message, $code, $userinfo)
Parameter Description
$message (string) The error message
$code (int) The error number
$mode (constant) Error mode
$options (mixed) Error mode specific parameters
$userinfo (mixed) additional data (ie. Debug information)
$errorclass (string) A class name
可选的你可以把已存在的毛病对象传递给这些函数:
&raiseError($error_object)
&throwError($error_object)
假如你从源代码对照这两个函数的参数表你将看到类并没有设置message参数――这是不用须的由于咱们在毛病类顶用 getMessage() 函数赋给毛病信息。并且,挪用PEAR机关函数来引入你的毛病类也是不用要的,你可以在对 raiseError() 挪用中指定毛病类。在头脑中记住这个选项!例如,假如你的类供应了静态函数或多于一个毛病对象,你不克不及给你的类像咱们在csv2db中做得那样全局地设置它们。
raiseError() 和 throwError() 可以被静态地挪用和像 setErrorHandling() 那样作为实体函数来挪用。当你作不作静态挪用地时分做准确地决意是主要的――它直接影响了用户若何用setErrorHandling()来错作咱们的类。寄望 setErrorHandling() 和 raiseError(),这将防止你和你的用户的头疼。
从类的这个局部可以看到全局和部分的毛病设置和触发的负面影响。
$storeMode = $GLOBALS['_PEAR_default_error_mode'];
$storeOpts = $GLOBALS['_PEAR_default_error_options'];
$GLOBALS['_PEAR_default_error_mode'] = $this->_default_error_mode;
$GLOBALS['_PEAR_default_error_options'] = $this->_default_error_options;
$db = DB::connect($dsn);
$GLOBALS['_PEAR_default_error_mode'] = $storeMode;
$GLOBALS['_PEAR_default_error_options'] = $storeOpts;
起首,全局的毛病形式被保留了,然后全局的毛病形式设置给下场部的毛病形式而且最初几行,本来的毛病形式被复原了。为何?Connect()是一个静态函数!它必需利用PEAR::raiseError()。因此假设咱们不保留而且复原设置,咱们会碰到成绩:看看listing 3――假如类在import()函数不克不及毗连到数据库的时分会产生甚么?由于对raiseError()的静态挪用遭到全局毛病形式的影响,而不是部分的$cd->setErrorHandling(...)的影响,剧本终止履行 。实践上push和popErrorHandling()就是设计来用于如许的义务的――然而PHP中一个现下的bug看上去不幸的组织了它很好的任务。
强迫$db对象利用咱们的毛病形式是更恬逸的体例,它撑持完全的PEAR Error API,这使得代码能如许写:$db->setErrorHandling($this->_default_error_mode, $this->_default_error_options)。两个实体变量都是由PEAR_Error类供应的。
那行$this->raiseError(corrupted record, CORRUPTED_RECORD)看上去值得注重――并且缺掉的前往看上去不顺眼。缘由是:咱们不想在发明破坏的纪录时中断函数履行。你能把这个和触发一个正告停止对比。独一的限制时形式PEAR_ERROR_RETURN没有任务。
Listing 3
<?php
...
PEAR::setErrorHandling(PEAR_ERROR_DIE)
$cd = new csv2db();
$cd->setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError');
$dsn = 'mysql://root@localhost/csv2db';
if( 0 < $d = $cd->import("./dat.csv", $dsn, 'address')) {
$cd->exportUnvalid("./dat2.csv");
}
$db = DB::connect($dsn);
$db->query(...);
...
function handleError($error) {
if(DB::isError($error) {
// handle database error
}
if(csv2db::isError($error) {
switch($error->getCode()) {
case FILE_NOT_OPENED :
...
break;
case CORRUPTED_RECORD :
...
break;
}
}
}
?>
PEAR毛病处置和PHP 5
由于咱们利用函数来创立毛病,咱们没有思索在PHP 5中的try/catch/throw机制;raiseMethod和throwError将为你完成这些!关于PHP 5,函数可以为你的类通明地挪用抛出PEAR_Error()――毛病形式PEAR_ERROR_EXCEPTION可以用于这个目标。一下的代码应当可以在不改动类的情形下用于PHP5中:
<?php
$i = new csv2db();
$dsn = 'mysql://root@localhost/csv2db';
try {
if( 0 < $d = $i->import("./dat.csv", $dsn, 'address')) {
$i->exportUnvalid("./dat2.csv");
}
}
catch CSV2DB_Error {
// fetch the error
}
?>
结论
我但愿你也许懂得了PEAR毛病处置,它供应了扫除和处置毛病的壮大机制。看看PEAR手册[1]的代码局部而且找出这些函数供应的优点。
Alexander Merz (alexmerz at php dot net) 是PEAR手册的编纂而且以自在创作者和作家为职业。
毕业设计作品自己个人还是觉得比较满意的,尽管有些功能考虑的不全面,也没有很好的实现。 |
|