The php anthology 2nd edition 2007 - phần 6 ppsx

55 228 0
The php anthology 2nd edition 2007 - phần 6 ppsx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

252 The PHP Anthology confusing way to express decision-making branches in your code, particularly when other methods are much more suitable (including testing return values from the function/method call, performing the various error method calls within the called function/method, and so on). Use exceptions when you can detect an event or condition in a unit of code that prevents any further execution. Good examples include: ■ database errors ■ web service call errors ■ filesystem errors (such as permissions, missing paths, and so on) ■ data encoding errors (until PHP 6 is out, that is) ■ parse errors (for example, when parsing configuration or template files) When used wisely and sparingly, exceptions become a very powerful error-handling tool. For more information on PHP exceptions, read the relevant PHP manual page. 5 How do I create a custom Exception class? The base Exception class provided in PHP 5 can be extended, but since exceptions bubble up the stack until they’re caught, why would you bother to create a custom Exception class? Well, if you use different Exception classes, it becomes much simpler to target specific types of exceptions and recover from them. Other reasons why you’d create a custom Exception class include: ■ You want to log specific types of exceptions. ■ You need to mail exception messages of particular classes. ■ You want to create special __toString output for pretty printing exceptions, or use exceptions in other specialized circumstances (for example, an XML-RPC client or server might use an exception class for fault responses, with the __toString method creating the XML fault response). 5 http://php.net/exceptions/ Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Error Handling 253 Solution Exception classes extend either the base PHP Exception class, or a class derived from it. To be able to catch your custom exception, all you need to do is extend it: class My_Exception extends Exception {} An exception that’s defined like this will act as would any other exception, though it can be type hinted as My_Exception when you’re catching exceptions: try { ⋮ try some code… } catch (My_Exception $e) { ⋮ handle exception… } The only overrideable methods in the Exception class are __construct and __toString. If you’re overriding the __construct method, your custom exception should call parent::__construct to ensure all data in the exception is properly set: class My_Exception extends Exception { public function __construct($message = null, $code = 0) { parent::__construct($message, $code); ⋮ do the rest of the initialization… } } Discussion It’ s useful to create exception classes to cover distinct groups of code that may span more than one class. For instance, if you were creating a suite of input filter classes, you may want to create a single exception class to cover them; however, if you’re creating an MVC (Model-View-Controller) suite, you may want a different type of exception class for each distinct area of the MVC pattern. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 254 The PHP Anthology Earlier, we mentioned logging and emailing exceptions. Unlike PHP errors, excep- tions are not logged, unless they remain uncaught, in which case they are logged as E_FATAL errors. Most of the time, you won’t want or need to log exceptions. However, some types of exceptions may indicate situations that need attention from a developer or sysadmin—for example, your script is unable to connect to a database (when PDO throws exceptions, not PHP errors, for instance), a web service is inac- cessible, a file or directory is inaccessible (due to permissions, or the fact that it’s simply missing), and so on. The easy way to handle these situations is to override the exception’s constructor to perform the notification task. Here’ s a custom exception class called My_Exception that calls the error_log function from within the constructor method: class My_Exception extends Exception { public function __construct($message = null, $code = 0) { parent::__construct($message, $code); error_log($this->getTraceAsString(), 3, '/tmp/my_exception.log'); } } While this is an easy method for performing special error-logging actions when ex- ceptions occur, I find that making the exception observable offers even more flexib- ility. Consider this usage example: Observable_Exception::attach(new Logging_Exception_Observer()); Observable_Exception::attach(new Emailing_Exception_Observer()); class Foo_Exception extends Observable_Exception {} ⋮ perform some work… throw new Foo_Exception('error occurred'); In this example, I’ve created a base exception class that’s observable, and called it Observable_Exception. I’ve attached two observers to this class: one that logs, and one that sends email. These observers check the type of the exceptions they observe, and use that information to decide whether or not to act. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Error Handling 255 This strategy provides some flexibility in terms of the way exceptions are handled, without requiring the use of an explicit exception handler. In addition, you can attach an observer anywhere in your code, which means that you can decide how to handle any given exception dynamically. The code that implements observable exceptions is as follows: Exception_Observer.class.php (excerpt) interface Exception_Observer { public function update(Observable_Exception $e); } This code defines the interface for exception observers. We’ll implement the Exception_Observer interface in a custom class in just a minute. Next, we create the Observable_Exception class by extending the Exception class. We add a static property—$_observers—to hold an array of Exception_Observer instances: Observable_Exception.class.php (excerpt) class Observable_Exception extends Exception { public static $_observers = array(); Next, a static method is used to attach observers. Type hinting enforces that only classes of the Exception_Observer type are allowed as observers: Observable_Exception.class.php (excerpt) public static function attach(Exception_Observer $observer) { self::$_observers[] = $observer; } We override the constructor method so that when the exception is instantiated all observers are notified via a call to the notify method: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 256 The PHP Anthology Observable_Exception.class.php (excerpt) public function __construct($message = null, $code = 0) { parent::__construct($message, $code); $this->notify(); } Finally, the notify method loops through the array of observers and calls their update methods, passing a self-reference to the Observable_Exception object, $this: Observable_Exception.class.php (excerpt) public function notify() { foreach (self::$_observers as $observer) { $observer->update($this); } } } Here’s an example of an exception observer: Logging_Exception_Observer.class.php (excerpt) require 'Exception_Observer.class.php'; require 'Observable_Exception.class.php'; class Logging_Exception_Observer implements Exception_Observer { protected $_filename = '/tmp/exception.log'; public function __construct($filename = null) { if ((null !== $filename) && is_string($filename)) { $this->_filename = $filename; } } public function update(Observable_Exception $e) { Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Error Handling 257 error_log($e->getTraceAsString(), 3, $this->_filename); } } This particular implementation of Exception_Observer logs exception information to a file. If you’re testing this code, make sure you set the $_filename variable to an appropriate location and filename. This strategy offers more flexibility than simply handling the logging or reporting in the constructor method of a custom exception class, or defining an exception handler function. Firstly, if you build a hierarchy of exception classes deriving from the Observable_Exception class, you can attach any number of observers to each type of observable exception, allowing for the customization of the exception envir- onment at any time without necessitating that changes be made to the actual excep- tion code. It also means that only the top-level exception class needs to contain any additional code; all classes that derive from that class can be empty stubs. Finally, each observer’ s update method can use type hinting via PHP’ s instanceof operator to decide whether or not any action needs to be taken. How do I implement a custom exception handler with PHP? A custom handler for PHP errors can be specified using the set_error_handler function. Exceptions bubble up until they’re caught, but what happens if they’re not caught? By default, any exception that isn’t caught raises an E_FATAL error. You could catch this error with a PHP error handler, but is there another way to handle uncaught exceptions? Solution Like PHP errors, exceptions can be handled automatically using a custom exception handler that’s specified with the set_exception_handler function. You’d typically implement an exception handler if you wanted your program to take a particular action for an uncaught exception—for example, you might want to redirect the user to an error page, or to log or email the exception so the developer can correct the issue. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 258 The PHP Anthology The basic approach involves providing a callback to set_exception_handler: null|string set_exception_handler(mixed callback) Discussion Since exception handlers handle any uncaught exception—not exceptions of specific types—they’re somewhat easier to implement than error handlers. In this example, we create a custom exception-handling class that logs uncaught exceptions to a file, and displays a simple error page: ExceptionHandler.class.php (excerpt) <?php class ExceptionHandler { protected $_exception; protected $_logFile = '/tmp/exception.log'; public function __construct(Exception $e) { $this->_exception = $e; } public static function handle(Exception $e) { $self = new self($e); $self->log(); echo $self; } The entry point for this exception handler is the static handle method, which in- stantiates itself, logs the exception, then displays an error message by echoing itself (using the magic __toString method). If you’re testing this code, make sure you set the $_logFile variable to an appropriate location and filename. This code uses PHP’s error_log function to log the exception backtrace to a file: Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Error Handling 259 ExceptionHandler.class.php (excerpt) public function log() { error_log($this->_exception->getTraceAsString(), 3, $this->_logFile); } The __toString implementation below creates a “pretty” error page that’ s displayed when an exception is handled, preventing the display to users of any sensitive in- formation contained in the exception backtrace: ExceptionHandler.class.php (excerpt) public function __toString() { $message =<<<EOH <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Error</title> </head> <body> <h1>An error occurred in this application</h1> <p> An error occurred in this application; please try again. If you continue to receive this message, please <a href="mailto:webmaster@example.com" >contact the webmaster</a>. </p> </body> </html> EOH; return $message; } } Finally, we tell PHP we want to handle exceptions using ExceptionHandler::handle: set_exception_handler(array('ExceptionHandler', 'handle')); Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 260 The PHP Anthology And we’re done! How can I handle PHP errors as if they were exceptions? Perhaps you prefer exceptions to PHP errors, and want to handle fatal or environ- mental PHP errors as if they were exceptions. No problem! Solution This task is relatively simple. We need to create a custom exception class and, to handle errors, we must add a public static method that throws an exception—that is to say, creates an instance of itself: ErrorToException.class.php (excerpt) class ErrorToException extends Exception { public static function handle($errno, $errstr) { throw new self($errstr, $errno); } } This class does not need to extend Exception in particular—just an Exception-de- rived class. You could, for instance, extend the Observable_Exception from “How do I create a custom Exception class?”. You won’t want to handle all PHP errors this way, though—E_NOTICEs and E_STRICTs don’t justify such handling. Fortunately, set_error_handler takes an error level as its second argument: set_error_handler( array('ErrorToException', 'handle'), E_USER_ERROR | E_WARNING | E_USER_WARNING ); The example code above dictates that only warnings and user errors will be thrown as exceptions. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Error Handling 261 Discussion While handling PHP errors as exceptions could be achieved even more simply using a function, rather than a static method, the approach I’ve explained here has several advantages. First, it allows you to type hint for these particular exceptions. Second, the exception class above could extend another custom exception class that provides additional functionality, such as the ability to log or mail exception information. How do I display errors and exceptions gracefully? You’ve taken heed of the advice to turn off display_errors on your production servers so that you don’t accidentally expose sensitive system information to users (and potentially hackers). If you’re not going to display errors, you’ll need to display something else instead. But how can you make this happen? Solution The solution to this common problem is to build the functionality into your error or exception handler. Displaying errors from an error or exception handler is a fairly trivial task, although you may need to take into consideration whether or not the error is fatal, and whether or not output buffering is being used. Since exception handlers are only triggered in the event of an uncaught exception, you can assume a fatal error when working with an exception handler; an example of an exception handler was shown in “How do I implement a custom exception handler with PHP?”. When you’re handling errors, however, you’ll need to check the error level of each error—you may want to display errors at some error levels, and not others, for example. The error-level checking can be done by testing the error level in your error handler, or by passing a second argument to set_error_handler to define which error levels the error handler should accom- modate. As for output buffering, we simply need to check the return value of ob_get_level. If that function returns zero, no output buffering is currently activated and we may Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... stored in the session, the method checks to see whether they’re available in the $_POST array; if they’re not, the method calls the redirect method Assuming the script has found the $_POST values, it calls the md5 function to get a digest for the password: Auth.class .php (excerpt) $password = md5($_POST[$var_pass]); We use the MD5 algorithm to store the password for security reasons, either in the session... methods by which PHP can keep track of the session ID: it can add the ID to the query string of all relative links on the page, or send the ID as a cookie Within the file that’s stored on the server, PHP saves the names and values of the variables it’s been told to store for the session When the browser makes a request for another page, it tells PHP which session it was assigned via the URL query string,... 274 The PHP Anthology Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com GET /subcat/98 HTTP/1.1 Host: www.sitepoint.com Here’s what it might receive from the server in return: HTTP/1.1 200 OK Date: Sat, 24 Mar 2007 08:12:44 GMT Server: Apache/2.0. 46 (Red Hat) X-Powered-By: PHP/ 4.3.11 Transfer-Encoding: chunked Content-Type: text/html; charset=ISO-885 9-1 . redirect the user to an error page, or to log or email the exception so the developer can correct the issue. Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 258 The PHP Anthology. Unregistered Version - http://www.simpopdf.com 260 The PHP Anthology And we’re done! How can I handle PHP errors as if they were exceptions? Perhaps you prefer exceptions to PHP errors, and want. Unregistered Version - http://www.simpopdf.com 268 The PHP Anthology Since exceptions are so easy to deal with, and since they allow code flow to continue from the point at which they’re caught,

Ngày đăng: 13/08/2014, 09:20

Từ khóa liên quan

Mục lục

  • The PHP Anthology

    • Table of Contents

    • Preface

      • Who Should Read this Book?

      • What’s Covered in this Book?

      • Running the Code Examples

      • The Book’s Web Site

        • The Code Archive

        • Updates and Errata

        • The SitePoint Forums

        • The SitePoint Newsletters

        • Your Feedback

        • Conventions Used in this Book

          • Code Samples

          • Tips, Notes, and Warnings

          • Introduction

            • Where do I get help?

              • Solution

                • RTFM: Read the Fine Manual

                  • I. Getting Started and II. Installation and Configuration

                  • III. Language Reference

                  • IV. Security

                  • V. Features

                  • VI. Function Reference

                    • PHP Extensions

                    • User Comments

                    • Other Resources

                    • What is OOP?

                      • Solution

                        • Classes Explained

                          • Encapsulation and Visibility

                          • Constructors and Destructors

Tài liệu cùng người dùng

Tài liệu liên quan