Exceptional Code: Error Handling In PHP 4 and PHP 5

zhaozj2021-02-16  100

By Matt Zandstra

July 29, 2004

Body, Center, TD, P, LI {Font-Family: Verdana, Arial, Helvetica, Sans-Serif; Font-size: 11px; Color: # 333333} ul {margin-left: 20;} h2 {font-family: Arial, Helvetica, Sans-Serif; Font-size: 16px; Color: # 336699} H3 {font-family: Arial, Helvetica, Sans-Serif; Font-size: 14px; Color: # 333333}

Intended Audience

Introduction

Error Handling Before PHP 5

?

Errors At Script Level

?

Returning Error Flags

Exceptions in PHP 5

?

Using the throw keyword

?

THE TRY-CATCH STATEMENT

?

Handling Multiple ErrorS

?

Subclassing Exception

?

Passing the buck

?

More information about an exception

Summary

About the Author

Intended Audience

This article is intended for experienced PHP programmers interested in learning more about PHP 5's new Exception support. You should be comfortable with the basics of object-oriented programming, including the anatomy of a class and the mechanics of inheritance.

Introduction

Most technical articles skimp on error handling. This is understandable since Tao lauses that check for error conditions tend to obscure otherwise good, clean example code. This article goes to the other extreme. Here you will encounter plenty of error handling, and very little else .

PHP 5 Introduced Exceptions, A New Mechanism for Handling Errors in An Object Context. AS You Will See, Exceptions Provides Provides Provides Provides Over More Traditional Error Management Techniques.

Error Handling Before PHP 5

Before The Advent of PHP 5 MOST Error Handling Took Place on Two Levels. You Could:

Return an error flag from your method or function, and perhaps set a property or global variable that could be checked later on, or Generate a script-level warning or a fatal error using the trigger_error () or die () functions.Errors at Script Level

You can use the die () pseudo-function to end script execution when there is no sensible way of continuing. You will often see this in quick and dirty script examples. Here is a simple class that attempts to load a class file from a directory :

cmddir} / {$ CMD} .php "; if (! File_exists ($ PATH)) {Die (" Cannot Find $ PATH / N ");} Require_once $ PATH; if (! Class_exists ($ cmd)) {Die (" Class $ CMD Does NOT EXIST ");} $ RET = New $ cmd (); if (! is_A ($ RET, 'Command')) {DIE (" $ cmd is not a command ");} RETURN $ RET;}}?>

This is a simplified example of what is known as the Command Pattern. The client coder can save a class to a command directory ( 'cmd_php4' in this case). As long as the file takes the same name as the class it contains, and this class is a child of a base class called Command, our method should generate a usable Command object given a simple string. The Command base class defines an execute () method, so we know that anything returned by getCommandObject () will implement execute ( ).

Let's look at the command class, Which we store in cmd_php4 / command.php:

as you can see, command is a php 4 Implementation of an abstract class . WHEN WE SHIFT over TO PHP 5 Later in The Chapter, WE WILL IMPLICITLY USE A Cleaner PHP 5 Version of this (Defined In Command / Command.php):

Here's A Vanilla Implementation of A Command Class. It is Called Realcommand, And Can Also Be Found in The Command Directory: CMD_PHP4 / Realcommand.php:

A structure like this can make for flexible scripts. You can add new Command classes at any time, without altering the wider framework. As you can see though, you have to watch out for a number of potential show stoppers. We need to ensure that The Class File EXISTS WHERE IT SHOULD, That The Class Itself is present, and then it subclasses command.

If any of our tests fail, script execution is ended abruptly. This is safe code, but it's inflexible. This extreme response is the only positive action that the method can take. It is responsible only for finding and instantiating a Command object. It has no knowledge of any steps the wider script should take to handle a failure, nor should it. If you give a method too much knowledge of the context in which it runs it will become hard to reuse in different scripts and circumstances.

Although using die () circumvents the dangers of embedding script logic in the getCommandObject () method, it nonetheless imposes a drastic error response on the script as a whole. Who says that failure to locate a command should kill the script? Perhaps a default Command SHOULD BE Used Instead, or Maybe The Command String Could Be reprocessed.We Could Perhaps make things a little more flexible by generating a user warning instead:

cmddir} / {$ CMD} .php "; if (! File_exists ($ PATH)) {Trigger_ERROR (" Cannot Find $ PATH ", E_USER_ERROR);} Require_once $ path; if (! Class_exists ($ cmd)) {Trigger_ERROR (" Class $ cmd does NOT EXIST ", E_USER_ERROR);} $ RET = New $ cmd (); if (! is_A ($ RET, 'Command')) {Trigger_ERROR (" $ cmd is not a command ", e_user_error);} Return $ Ret; }}?>

. If you use the trigger_error () function instead of die () when you encounter an error, you provide client code with the opportunity to handle the error trigger_error () accepts an error message, and a constant integer, one of:

E_USER_ERRORA FATAL ERRORE_USER_WARNINGA NON-FATAL ERRORE_USER_NOTICEA Report That May Not Repersent An Error

You can intercept errors generated using the Trigger_ERROR () Function by Associating a Function with set_error_handler ():

getcommandObject ('realcommand'); ? $ cmd-> execute ();> As you can see, set_error_handler () accepts a function name If an error is triggered, the given function is invoked with four arguments: the error flag, the message, the file, and the. line number at which the error was triggered. You can also set a handler method by passing an array to set_error_handler (). The first element should be a reference to the object upon which the handler will be called, and the second should be the name Of The Handler Method.

Although you can do some useful stuff with handlers, suchputting debug data and sofore, the remain a pretty crude way of handling errors.

Your options are limited as far as action is concerned. In catching an E_USER_ERROR error with a handler, for example, you could override the expected behavior and refuse to kill the process by calling exit () or die () if you want. If you Do this, you must reconcile yourself to the Fact That Application Flow Will Resume WHERE IT LEFT OFF. THIS COULD CAUSE SOME PRETTY TRICKY BUGS IN CAUSE EXPECTS An Error To End Execution.

Returning Error Flags

Script level errors are crude but useful. Usually, though, more flexibility is achieved by returning an error flag directly to client code in response to an error condition. This delegates error handling to calling code, which is usually better equipped to decide how to react (false is usually a good name.) (false is usually a good name.)

cmddir} / {$ CMD} .php "; if (! file_exists ($ path)) {RETURN FALSE;} Require_once $ path; if (! Class_exists ($ cmd)) {Return False;} $ RET = New $ cmd (); if (! IS_A ($ RET, 'Command')) {RETURN FALSE;} RETURN $ RET;}}?>

This Means That You Can Handle Failure In Different Ways According to Circumstances. The Method Might Result In Script Failure:

getcommandObject ('realcommand'); if (is_bool ($ cmd)) {Die ("Error getting command / n");} Else {$ cmd-> EXECUTE ();}?>

or just a logged error:

getcommandObject ('realcommand'); if (is_bool ($ cmd)) {Error_Log ("Error getting command / n", 0) } Else {$ cmd-> execute ();}?>

One problem with error flags such as false (or -1, or 0) is that they are not very informative You can address this by setting an error property or variable that can be queried after a failure has been reported:. error_str = get_class ( $ this). ": $ msg";} Function Error () {Return $ this-> Error_Str;} Function getcommandObject ($ cmd) {$ PATH = "{$ this-> cmddir} / {@cmd }.php "; if (! File_exists ($ PATH)) {$ this-> setError (__ function__," cannot find false;} require_once $ path; if (! Class_exists $ cmd)) {$ this-> setError (__ function__, "class $ cmd does not exist"); return false;} $ RET = new $ cmd (); if (! is_a ($ RET, 'Command')) { $ THIS -> setError (__ function__, "$ cmd is not a command"); return false;} RETURN $ RET;}}?>

This simple mechanism allows methods to log error information using the setError () method. Client code can query this data via the error () method after an error has been reported. You should extract this functionality and place it in a base class that all objects in your scripts extend. If you fail to do this, client code might be forced to work with classes that implement subtly different error mechanisms. I have seen projects that contain getErrorStr (), getError (), and error () methods in different classes .

It is not always easy to have all classes extend the same base class, however. What would you do, for example, if you want to extend a third party class? Of course, you could implement an interface, but if you are doing That, THEN You Have Access To PHP 5, And, AS We Shall See, PHP 5 Provides a better Solution Altogether.

You can see another approach to error handling in the PEAR packages When an error is encountered PEAR packages return a Pear_Error object (or a derivative) Client code can then test the returned value with a static method:.. PEAR :: isError (). IF an error haas been encountered

Pear_rror (if any) - the error code (if any) - the error code (if any) - the error code (if any) - the error code (if any) :: getTyper :: gettyper :: getTyper :: get er erf :: getcode (if any)

Here We alter the getcommandobileObject () Method SO That It Returns a pear_error Object When Things Go WRON:

cmddir} / {$ cmd} .php "; if (! file_exists ($ PATH)) {Return Pear :: RaiseError (" Cannot Find $ PATH ");} Require_once $ PATH; if (! Class_exists ($ CMD)) {RETURN PEAR :: RaiseError ("Class $ CMD Does Not Exist";} $ RET = New $ CMD (); if (! is_A ($ RET, 'Command')) {Return Pear :: raiseerror "$ cmd is not a command");} RETURN $ RET;}}?>

Pear_Error is neat for client code because it both signals that an error has taken place, and contains information about the nature of the error. getCommandObject ('Realcommand'); IF (Pear :: ISERROR ($ cmd)) {Print $ cmd-> getMessage (). "/ n"; exit;} $ cmd-> execute ();?>>

Althube Returning An Error Value Allows You To Respond To Problems Flexibly, IT Has The Side Effect of Polluting Your Interface.

PHP does not allow you to dictate the type of value that a method or function should return, in practice, though it is convenient to be able to rely upon consistent behavior. The getCommandObject () method returns either a Command object or a Pear_Error object. If you intend to work with the method's return value you will be forced to test its type every time you call the method. A cautious script can become a tangle of error check conditionals, as every return type is tested.

Consider this Pear :: DB Client Code Presented WITHOUT ERROR Checking:

Query ("Create Table Records") ")") ")") ")") ")"); $ INSERT_RESULT = $ DB-> Query ("INSERT INTO RECORDS VALUES (" 'OK Computer') "); $ query_result = $ db-> query (" Select * from records "); $ row = $ query_result-> fetchrow (db_fetchmode_assoc); Print $ ROW ['Name']." / n "; $ Drop_Result = $ DB-> Query ("Drop Table Records"); $ db-> disconnect ();?>

. The code should be readable at a glance We open a database, create a table, insert a row, extract the row, and drop the table Look what happens when we code defensively:. getMessage ());} $ INSERT_RESULT = $ DB-> Query ("INSERT INTO RECORDS VALUES"); if (DB :: ISERROR ($ INSERT_RESULT) ) {DIE ($ INSERT_RESULT-> GetMessage ()); $ query_result = $ db-> query ("Select * from records"); if (db :: iesrror) {Die ($ query_result-> getMessage ()); $ row = $ query_result-> fetchrow (db_fetchmode_assoc); Print $ ROW ['Name']. "/ n"; $ Drop_Result = $ DB-> Query ("DROP TABLE RECORDS"); IF (DB :: ISERROR ($ Drop_Result) {Die ($ DROP_RESULT-> getMessage ()); $ db-> disconnect ();?>>

Admittedly, WE Might Be a little less Paranoid THIS IN Real-World Code, But this SHOULD ILLUSTRATE The Tangle That Can Result from Inline Error Checking.

So what we need is an error management mechanism That:

Allows a method to delegate error handling to client code that is better placed to make application decisions Provides detailed information about the problem Lets you handle multiple error conditions in one place, separating the flow of your code from failure reports and recovery strategies Does not colonize the Return Value of a Method

PHP 5's Exception Handling Scores on All these Points.exceptions in PHP 5

We have now discussed error handling in some detail. Although we have yet to encounter our first exception (!), The ground we have covered should go some way to illustrating the needs that exceptions meet.

The Built-in Exception Class Includes The Following Methods:

__construct () The constructor. Requires a message string and an optional integer flag.getMessage () The error message (as passed to the constructor) getCode () The error code (as passed to the constructor) getFile () Returns the path for the file in which the Exception was generated.getLine () Returns the line number at which the Exception was generatedgetTrace () An array that provides information about each step in the progress of an ExceptiongetTraceAsString () As getTrace () but in string format

As you can see, The Exception Class Is Similar in Structure To Pear_ERROR. WHEN YOUNCOUNTER An Error In Your Script You Create Your OWN Exception Object:

$ EX = New Exception ("COULD NOT OPEN $ THIS-> File");

.

Using the throw keyword

Having created An Exception Object You Could The Return It As You Might A Pear_ERROR Object, But You Shouldn't! Use the throw keyword instead. Throw is buy with an exception Object:

Throw New Exception ("My Message", 44);

Throw Ends Method Execution Abruptly, And Makes The Associated Exception Object Available To The Client Context. Here's Our getcommandObject () Method Amended To Use Exceptions:

cmddir} / {$ CMD} .php "; if (! file_exists ($ PATH)) {throw new exception;} Require_once $ path; if (! Class_exists ($ cmd)) {throw new Exception (" Class $ CMD Does Not Exist ");} $ CMD); if (! $ class-> issubclassof (New Reflection")) {throw new exception ("$ cmd is not a commnd") ;} return new $ cmd ();}}> We use ReflectionClass from the Reflection API to check that the given class name belongs to the Command type Running this code with an invalid file path will result in an error like this?.:

Fatal error: Uncaught exception 'Exception' with message 'Can not find command / xrealcommand.php' in /home/xyz/BasicException.php:10 Stack trace: # 0 /home/xyz/BasicException.php(26): CommandManager-> GetcommandObject ('XRealcommand') # 1 {main} thrown in /Home/xyz/basicexception.php on line 10

As you can see, throwing an Exception results in a fatal error by default. This means that code that uses exceptions has safety built-in. An error flag, on the other hand, does not provide any default behavior. Failure to handle an error Flag SIMPLY Allows your script to payue execution using an inappropriate value.

THE TRY-CATCH STATEMENT

In order to handle an Exception at the client end, we must use a try-catch statement. This consists of a try clause and at least one catch clause. Any code that invokes a method that might throw an Exception should be wrapped in the try . clause The catch clause is used to handle the Exception should it be thrown Here's how we might handle an error thrown from getCommandObject (): getcommandObject ('NREALCOMMAND'); $ cmd-> execute ();} catch (exception $ e) {print $ e-> getMessage (); exit ();}?>

As you can see, the Exception object is made available to the catch clause via an argument list similar to the kind you might find in a method or function declaration. We can query the provided Exception object in order to get more information about the error. By Using The Throw Keyword In Conjunction with the try-catch statement we avoid pointuting Our method's return value with an error flag.

IF An Exception Is Thrown, Execution With Clause Will Cease Abruptly, And Flow Will Switch Immediately to the catch clause.

As We Have Seen, IF AN Exception is Left Uncaught, A Fatal Error Results.

Handling Multiple ErrorS

Exception handling so far has not been so different from code that checks return values ​​for error flags or objects Let's make the CommandManager class a bit more cautious, and have it check the command directory in the constructor.:

cmddir) {throw new Exception ("Directory Error: $ THIS-> CMDDir");}} Function getcommandObject ($ cmd) {$ path = "{$ this-> cmddir} / {$ cmd} .php"; if (! File_exists ($ PATH) ("Cannot_Once $ PATH; IF (! Class_exists ($ cmd)) {throw new exception (" Class $ cmd does not exist ";} $ class = new reflectionClass $ cmd); if (! $ class-> issubclassof (New Reflection ")) {throw new exception (" $ cmd is not a command ");} return new $ cmd ();}}?> there Are Now Two Invocations That Might Cause, We don't need to change our client code at all. You can include as many statements as you want in a try clause, and still hand e all errors in one place. If the CommandManager object's constructor throws an exception then execution in the try clause stops, and the catch clause is invoked with the relevant Exception object. The same is true of the getCommandObject () invocation. So we have two Potential Causes of Error In One Place, And A Single Clause for Managing Any Problems In another. this allows you to write cleaner code knitting.

getcommandObject ('realcommand'); // another potential error $ cmd-> execute ();} catch (Exception $ E) {// Handle Either Error Here Print $ E-> getMessage (); exit ();}?> There is one proBLETWEEN DOW We distinguish Between Different Types of error? For Example, We May wish to DEAL WITH A MISSING DIRECTORY INE WIY, AND An Illegal Command Class in Another.

............................

cmddir) {Throw New Exception ("Directory Error: $ this-> cmddir", self :: cmdman_general_error);}}} function getcommandObject ($ cmd) {$ PATH = "{$ this-> cmddir} / { $ cmd} .php "; if (! file_exists (" Cannot Find $ PATH ", Self :: cmdman_illegalclass_error);} Require_once $ path; if (! Class_exists ($ cmd)) {throw new Exception ( "class $ cmd does not exist", self :: CMDMAN_ILLEGALCLASS_ERROR);} $ class = new ReflectionClass ($ cmd); if {throw new ($ class-> isSubclassOf (new ReflectionClass ( 'Command'))!) Exception ("$ cmd is not a command", self :: cmdman_illegalclass_ERROR);} Return $ Class-> NewInstance (); }}?> By passing one of CMDMAN_ILLEGALCLASS_ERROR or CMDMAN_GENERAL_ERROR to any Exception object that we throw, we make it possible for client code to recognize different error categories, and define distinct strategies for handling the problem.

getcommandObject ('realcommand'); $ cmd-> execute ();} catch (exception $ e) {= E-> getcode () == comMMandManager :: cmdman_general_ERROR) {// no way of recovering die ($ E-> getMessage ());} else if ($ e-> getcode () == commandManager :: cmdman_illegalclass_ERROR) { error_log ($ e-> getMessage ()); print "attempting recovery / n"; // perhaps attempt to invoke a default command}}> We can achieve a similar effect by throwing and catching distinct Exception subclasses??.

Subclassing Exception

There Are Two Clear Reasons Why You Might Want To Subclass Exception. There Are:

To provide Specialized Functionality Within your subclass to distinguish one error Type from another as a service to client code.

Let's look at the second instance We might work with two kinds of error in the CommandManager class:. A general error category (covering a missing command directory, for example), and a set of errors associated with the failure to locate or generate Command objects .

WE Might Define Two Exception Subtypes for these Cases:

CMDDIR)) {Throw New CommandManageRexception ("Directory Error: $ this-> cmddir");}}} Function getcommandObject ($ cmd) {$ Path = "{$ this-> cmddir} / {$ cmd} .php "; if {throw new IllegalCommandException (file_exists ($ path)!) (" Can not find $ path ");} require_once $ path; (! class_exists ($ cmd)) if {throw new IllegalCommandException (" class $ cmd does NOT EXIST ");} $ CLASS = New ReflectionClass ($ CMD); if (! $ Class-> Issubclassof (New Reflection")) {throw new illegalcommandexception ("$ cmd is not a command");} Return $ class-> newinstance ();}}?> when}} to find a comm disposed directory it throws a CommandManagerException. When it encounters difficulties in generating a Command object, the getCommandObject () method throws an IllegalCommandException. Note that there are a number of different reasons why an IllegalCommandException might be thrown. We could combine the two previous examples here and Provide An Error Code Constant In The IllegalCommandexception for Each Potential Cause.

Now That The CommandManager Class Can Fail In There Novel Ways To match The Different Error Types:

getcommandObject ('realcommand'); $ cmd-> execute ();} catch (commandmanagerexception $ e) {die ($ E-> getMessage ();} catch (IllegalCommandexception $ E) {Error_Log ($ E-> getMessage ()); Print "Attempting Recovery / N"; // Perhaps Attempt to Invoke A Default Command?} catch (Exception $ e) {print "Unexpected exception / n"; die ($ e-> getMessage ());}> If the CommandManager object above throws a CommandManagerException, then the corresponding catch is executed This is not a given, however The?.. . argument portion of each catch clause acts like a test The first match is the one executed For this reason, you should always organize your catch clauses from the most specific to the most general If we were to reorganize our catch clauses like this..:

getcommandObject ('realcommand'); $ cmd-> execute ();} catch (Exception $ e) {print "unExpected Exception / N "; DIE ($ E-> getMessage ());} catch ($ e-> getMessage ());} catch (IllegalCommandexception $ E) {Error_Log ($ E-> GetMessage ()); Print "Attempting Recovery / N"; // Perhaps Attempt to Invoke A Default Command?}?>

...................

If you are catching specific Exception subtypes in your catch clauses, it is a good idea to implement a final clause that catches the Exception type. This then acts as a catch-all. Of course, you may wish to pass the buck along to the Method That Called The Client Code. this is another feature of php's exception functionality That Should Be Discussed.Passing The Buck

We have already established that some errors can not be handled at the point at which they occur. A good solution to this can't-see-the-wood-for-the-trees scenario is to pass responsibility back up to the code that called the current method. What happens, though, if the calling code does not itself have the perspective to deal with the problem? Well, we can always re-throw the error. Let's expand the client code we have been working with so that it forms Part of a Simple Class:

request = $ Request_Array)) {$ this-> Request = $ _ request;}} Function getcommandstring () {return ($ this-> cmdstr? $ this-> cmdstr: ($ this-> cmdstr = $ this-> request ['cmd ']));} Function Runcommand () {$ cmdstr = $ this-> getcommandstring (); try {$ mgr = new commandmanager (); $ cmd = $ mgr-> getcommandObject ($ cmdstr); $ cmd-> execute ();} Catch (IllegalCommandexception $ E) {Error_Log ($ E-> getMessage ()); if ($ cmdstr! = $ This-> defaultcmd) {$ this-> cmdstr = $ this-> defaultcmd; $ this- > Runcommand ();} else {throw $ e;}} catch (Exception $ e) {throw $ E;}}} $ helper = new r Equesthelper (Array (cmd => 'realcommand')); $ helper-> runcommand ();?>

We have wrapped our client code in a class called RequestHelper. The RequestHelper class is responsible for managing user-provided data. In the constructor we optionally accept a debug array. If no such array is forthcoming, the class uses the superglobal $ _REQUEST array. whichever array is used, it is assigned to a property called $ request. Client code signals the command it wishes to execute by providing a 'cmd' element in the request array. The getCommandString () method tests a property called $ cmdstr. If it is empty (which it is, to start with) then the method assigns the contents of the $ request property's 'cmd' element to $ cmdstr, returning the result. If it is not empty, the method simply returns the $ cmdstr property. Through this mechanism, the command string can be overridden within the RequestHelper class.RequestHelper has a relatively narrow remit, so for all exceptions but IllegalCommandException objects we defer any error handling to a higher level class. We do this in the Final catch clause by manually throwing the caught exception class:

} catch (Exception $ E) {throw $ E;}

If we catch an IllegalCommandException, however, we first attempt to invoke a default command. We do this by setting the $ cmdstr property to the same value as $ defaultcmd and then invoking the runCommand method recursively. If the $ cmdstr and $ defaultcmd strings are Already Equivalent, There is no further action we can take, and we re-throw the exception.

In fact Zend Engine 2 will automatically re-throw any exceptions that you do not catch yourself, so we could omit the final catch clause altogether with no change in script functionality. (We have already taken advantage of this feature in our example.) Here is the final line of the commandmanager :: getcommandObject () Method: Return $ Class-> NewInstance ();

We Beg a couple of qustions.

Firstly, We Have Assumed That The Constructor Requires No Arguments. In this article we will not dead..............

Secondly, we have assumed that the command can be instantiated. If the constructor was declared private, for example, this statement would throw a ReflectionException object. If we do not handle this in RequestHelper, then the exception will be passed up to the code that invoked RequestHelper, and so on. Where an exception may be thrown implicitly it is a good idea to signal as much in your documentation, or even to manually throw the exception so that other programmers are forewarned to handle this eventuality.

More information about an exception

Here Is Some Code That Formats Exception Information.

'realcommand ")); $ helper-> runcemmand ();} catch (Exception $ E) {Print "

". GET_CLASS ($ E). " / n"; print "

{$ E-> getMessage ()} ({$ E-> getcode ()} / n / n "; print" file: {$ E-> getFile ()}
getLine ()}
getTraceAsString (); die;}}} Front :: main ();> If you make the realcommand class impossible to instantiate (by declaring its constructor private) and run this code, you will see this output:

ReflectionException

Access to non-public constructor of class realcommand (0) file: /Home/xyz/tracestacked ipption.php
line: 30
# 0 /home/xyz/TraceStackException.php(53): CommandManager-> getCommandObject () # 1 /home/xyz/TraceStackException.php(73): RequestHelper-> runCommand ( 'realcommand') # 2 / home / xyz / TraceStackException. PHP (85): front :: main () # 3 {main}

As you can see, getFile () and getLine () do just what you would expect:. They return the file name and line number for the exception The getStackAsString () method returns details about each layer of invocation that led to the exception's generation.

You can also get at this information in array format using the getTrace () method. GetTrace () returns a multi-dimensional array. As you'd expect, the first element contains information about the location at which the exception is generated, the next . element details the outer method call, and so on until the topmost level is reached Each element in this array is itself an array with the following fields: fileThe file in which the method invocation was madelineThe line number of the offending method callfunctionThe name of the Offending methodclassthe class on which the invocation tasmtypethe Kind of call, '::' for static, or '->' for instance invocationsargs the arguments for the Method Call

Summary

Exceptions provide some key benefits.

By grouping error handling code in catch statements you can separate your error handling from your application flow. This can make your code easier to read, and your coding practice more pleasant. I often begin with a strict policy of catching all exceptions in a method and Killing Script Execution. I THEN INTRODUCE ADDITIONAL FLEXILITY AS NEEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDEDs the AND Easy Exception Management Straight Away.

Exceptions flow from the low level to the high. That is, exceptions are passed back to the code that is best placed to decide how to handle an error. At first it may seem to defy common sense, but it is usually the case that the Point at Which An error Occurs is The Worst Place to Decide What To Do About The Error.

The throw / catch mechanism provided by exceptions sidesteps the problems associated with returning error values ​​from methods. The return value of a method can be determined entirely by the logic of your class. Client code can expect a particular return type, without the wearisome task of Continual Testing.about the Author

Matt Zandstra is a writer and consultant specializing in server programming and training. With his business partner, Max Guglielmino, he runs Corrosive, a technical agency that provides open source / open standards training and plans, designs and builds Internet applications.

Matt Is The Author of Sams Teach Yourself PHP in 24 Hours. He Is Currently Working ON A Book About Object-Oriented PHP.

转载请注明原文地址:https://www.9cbs.com/read-11325.html

New Post(0)