Take a closer look at Pear's error handling

Source: Internet
Author: User
Tags error code error handling execution functions getmessage connect mysql string
Error | Error handling pear provides a powerful error-handling mechanism. This article shows you how to benefit from this system.


Many programs already use Pear's package. Many PHP programmers are more or less familiar with the error handling in pear. But this mechanism is not limited to Pear's package--everyone can use these methods in their classes and programs.

This article is divided into two sections: first we'll look at the functions used in the class for error handling, and then we'll see how to handle errors based on the pear error handling mechanism.

Our example class is called CVS2DB, which inserts data from a CSV file into a database table. Since the data may be handwritten, their data should be validated prior to insertion-implementing postcode. Function Import () completes the read, check, and insert work; it returns the number of corrupted records. If the returned value is greater than 0, the error Recordset can be written to the new CSV file using Exportunvalid (). The typical usage is this:

<?php
$CD = new csv2db ();
$dsn = ' mysql://root@localhost/csv2db ';
if (0 < $CD->import ("./dat.csv", $DSN, ' address ')) {
$CD->exportunvalid ("./dat2.csv");
}
?>


Possible errors include the following:

The CSV file you are importing does not exist.
Failed to connect to the database,
The recordset is corrupted, and the CSV export file cannot be created.

You might write this code in a classic solution that provides error messages:

<?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! '
}
}
?>


This is an acceptable and commonly used method for short scripts-but not for large programs that are often concerned about error handling. The traditional possibility of forcing the author of the class to make the final decision! In most cases, this decision is based on the idea of a call to a class at that time rather than based on long-term usage and reusable code. A flexible error-handling mechanism is an important part of reusable code, and the PEAR error API is such a good test mechanism.


The class in the eyes of the user

In addition to those two functions, the class provides a set of error-handling functions and one of its own error objects called Db2cvs_error, which has a special feature of localized error messages.

Now I'm going to show you how to control the behavior of the class when the error occurs.

Local and global error handling

You use Seterrorhandling () to manage error handling; This function requires two parameters: the first is the error pattern, and the second (optional) parameter is the error mode-specific option. For example seterrorhandling (Pear_error_print, ' This ERROR occurred%s ') and seterrorhandling (Pear_error_trigger, e_user_warning )。


This function is invoked in the most important way in general behavior: Static or entity. In class cvs2db, we can use both to set error handling, all of which have the same structure--set the error mode for the class:

Per instance
$CD = new csv2db ();
$CD->seterrorhandling (Pear_error_die):
Static
Cvs2db::seterrorhandling (Pear_error_die);
Pear::seterrorhandling (Pear_error_die);


If the two give the same result, where is the difference? An entity call is only set for that class and the static call works for all classes that use Pear_error or derive from that class. This also applies to the first static command Cvs2db::seterrorhandling (Pear_error_die)-although it appears to affect only the Cvs2db class.


Summary: Using a command as an entity function means that only the error pattern is set for the entity (local), and as a static function, the error mode (global) is set for the entire script.


Seterrorhandling () and RaiseError ()


All two functions can be called by static calls and functions that act as entities. It's important to remember how a combination makes them interact with each other.

Basically: the static invocation of seterrorhandling () only affects the static invocation of RaiseError ()--seterrorhandling () as the entity function only affects raiseerror () as a static function call. In class csv2db, it is not feasible to use csv2db::seterrorhandling () to set the error mode because we use $this->raiseerror (...). There's a little trick to solving this US-rewrite 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,...);
}


In this way, we map the entity call to static, if you call RaiseError () in error mode, then this pattern will overwrite these settings--here is the global setting.

You should be careful how the errors are thrown by the class, and if you are not careful, this can cause unexpected side effects.


Wrong pattern

An understanding of the error pattern is important for using Pear's error handling. Pear error handling allows the user to decide what to do-note: The term user is referring to the developer who actually uses the Pear_error program rather than the user who browses the script results or the Web page. I'll show you the possible error patterns in detail.

pear_error_die--This mode on, the program ends and the error message is printed. Optionally, you can define a printf () string that can be used to generate information; First '%s ' in the string replaces the error message in the stored Error object.

pear_error_print--only prints error messages, including the same optional strings used for Pear_error_die.

pear_error_return--The general behavior when the error occurs; You can use the class to provide the IsError () function or pear::iserror () to check for errors.

$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--Here the function is the same as the run-time error behavior of PHP. You must define what kind of error should occur: E_user_notice,e_user_warning or E_user_error. They correspond directly to the information generated by PHP itself. Note that the line in which the error occurred in the error message (XXX on lines yy) refers to the line that calls the Trigger_error in the pear.php-not the line where the error occurred directly.

pear_error_callback--This is the best way to handle errors in one place and let you get code without thinking about error handling. It requires a function or class function to catch errors, and you can write a script like the one shown in Listing 2, where you can see the benefits of a class-related Error object: the import () function throws a csv2db_error to a CSV based error and a db_ The Error object gives errors related to database access.

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
}
}
}


Single Error handling

We have two possible errors: errors that we can ignore (corrupted records), and errors that make the program impossible to run (files cannot be found or databases cannot be opened). If you use a class in a shell script, you can let the script terminate with the second type of error.

Naturally, you can write $CD->seterrorhandling (Pear_error_die)--but this may cause problems if a corrupted record error occurs. In this case you need to deactivate or replace the possibility of error handling for an error. Solution when Expecterror (), if you pass an error code to this function, the error pattern that specifies the error will be set to Pear_error_return alone in the default error mode.

The Expecterror () function stores the error code passed in the stack, using popexpected () to move out the last-passed error code. since PHP 4.3 you have been able to use Delexpect (), this function removes the specified error code from the stack, and you don't need to be concerned about the location.

In actual use, this is the case:

$CD->seterrorhandling (Pear_error_die);
...
$CD->expecterror (Corrupted_record);
$CD->import (...);
$CD->popexpect ();


Pusherrorhandling () and poperrorhandling () are similar to each other, and they can temporarily control error handling. For example, if the file in Exportunvalid () cannot be opened, you want to ignore the error:

PEAR::p usherrorhandling (Pear_error_return);
$CD->exportunvalid ("./dat2.csv");
PEAR::p operrorhandling ();


Note the difference between calling methods! Expecterror ()/popexpect () must be called as an entity function to invoke--pusherrorhandling and poperrorhandling can be invoked statically. If they are entity functions, then they only affect that entity.

Users have a lot of possibilities, does that mean that programmers do a lot of work? Yes, it's because you're doing more than return false, no, because the Pear Error API has done a lot of work for you.


Some thoughts about error handling

As a good programmer, you should not hide the exact cause of the error from the eyes of the user of your class. This prevents the use of simple return false, as well as the possibility of being converted to 0--by the PHP auto type, which means that all records have been inserted correctly for the import () function! Simply terminate the script? , which may be acceptable for simple PHP shell scripts, but a bad choice for a Web application! Also, errors can be ignored in cases where the corruption is logged. What doesn't trigger_error ()? This is a possible choice, but there are two drawbacks: the behavior of the class depends on the php.ini settings, and this behavior is uncommon for classes. The possibility of using additional functions to find the wrong state. Even though all classes provide nonstandard function names, this is problematic, and users of the class seem to forget such function calls-as shown in mailing lists and newsgroups. What to do? Let the user decide the Pear error handling API. The pear error system is widely known and many classes already use the Pear class, so we have to use the pear error handling mechanism Anyway-why not build on it? This avoids the problems mentioned earlier and provides a great possibility for the user. Look at listing 1, which shows the implementation of the CSV2DB class and its error objects. It may be a little scary, but we'll go through the source code in one line.

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];
}
}
?>


Your own Wrong object

Having one's own error class is always good, although it may be too much of an extra burden for such a small class-but this class is just an example and you can benefit a lot from the features that require lots of code without the wrong objects. The advantage is that the first error is assigned directly to the class, and localization becomes easier.

Class must inherit from Pear_error in order to keep our implementation simple, otherwise pear::iserror () will not work properly.

The implementation contains the constructor, which is not changed to pass the parameter to the Pear_error constructor.

Overwriting the GetMessage () function is key to providing localized error information. Error Dingxi is defined as a variable of the class and will depend on the dynamic assignment of the language. This also gathers help messages in one place-rather than spreading them across the source code of the main class.

Implementing Pear Error Handling

You see in the first part of the article that our class provides a bunch of functions--but only four of them are implemented directly. Error handling for all related functions is provided by the Pear base class. To benefit from all of those error-handling features, we must let the Cvs2db class inherit from the Pear base class, which is: Class Csv2db extends Pear.

In the previous section of the wrong object, I started with an explanation of IsError (). Overwriting this method is not necessary, although it does allow us to check our error classes directly and make error tracking more accurate and may save a few milliseconds.

The constructor of a class simply invokes the constructor of the parent class with the most parameter of the wrong class name. This call registers our Error object and ensures that our error class is used every time the error is triggered.


RaiseError

The use of RaiseError () in the function body of import () and Exportunvalid () is noteworthy. This is the key function to create the error; Pear provides two functions for this purpose: RaiseError () and ThrowError (). The latter is a simplified variant of the raiseerror () that has been in existence since PHP 4.3, and their parameters are described in the paragraphs ' RaiseError and ThrowError '.


RaiseError and ThrowError

Prototype:

&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


Optionally, you can pass the existing error objects to these functions:

&raiseerror ($error _object)
&throwerror ($error _object)


If you compare the parameter tables of these two functions from the source code you will see that the class does not set the message argument--this is not necessary because we assign the error information to the GetMessage () function in the error class. Also, calling the pear constructor to introduce your error class is unnecessary, and you can specify the error class in the RaiseError () call. Remember this option in your mind! For example, if your class provides static functions or more than one Error object, you cannot set them globally as we do in csv2db.

RaiseError () and ThrowError () can be invoked statically and as entity functions as seterrorhandling (). It is important to make the right decision when you do not make a static call-it directly affects how the user uses seterrorhandling () to make the wrong class. Pay attention to seterrorhandling () and RaiseError (), which will avoid headaches for you and your users.

From this part of the class, you can see the negative effects of global and local error settings and triggers.

$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;


First, the global error pattern is saved, then the global error mode is set to the local error pattern and the last few lines, the original error mode is restored. Why? Connect () is a static function! It must use Pear::raiseerror (). So if we don't save and restore the settings, we'll have a problem: look at listing 3--what happens if the class is not connected to the database in the import () function? Because static calls to RaiseError () are affected by the global error pattern, rather than the local $cd->seterrorhandling (...) effect, the script terminates execution. In fact, push and poperrorhandling () are designed to be used for such tasks-but a bug in PHP now looks unfortunate enough to organize it to work well.

Forcing the $db object to use our error mode is a more comfortable way to support the full pear error API, which allows the code to write this: $db->seterrorhandling ($this->_default_error_mode, $ this->_default_error_options). Two entity variables are provided by the Pear_error class.

That line of $this->raiseerror (corrupted record, Corrupted_record) looks noteworthy-and the missing return looks uncomfortable. The reason: We don't want to abort the function execution when we find the corrupted record. You can compare this with triggering a warning. The only restricted time mode Pear_error_return is not working.

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 error Handling and PHP 5

Because we use functions to create errors, we do not consider the try/catch/throw mechanism in PHP 5; Raisemethod and ThrowError will do this for you! For PHP 5, a function can transparently invoke your class to throw pear_error ()--error mode pear_error_exception can be used for this purpose. The code should be able to be used in PHP5 without changing the class:

<?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
}
?>


Conclusion

I hope you know about Pear error handling, which provides a powerful mechanism for troubleshooting and handling errors. Look at the code section of the Pear Manual [1] and find out the benefits that these functions provide.

Alexander Merz (alexmerz at php dot net) is the editor of the Pear Handbook and is a freelance creator and writer.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.