Each new feature added to the PHP runtime creates an exponential random number, in such a way that developers can use and even abuse this new feature. However, it was not until some good and bad usage occurred that the developers reached a consensus. As these new cases continue to emerge, we can finally tell what is best or worst.
Exception handling is really not a new feature in PHP anyway. But in this article, we'll discuss the two new features that are based on exception handling in PHP 5.3. The first is a nested exception the second is a set of SPL (now a core extension of PHP's operating mechanism) that extends the new exception type. These two new features, this book can find the best practice worthy of you to study in detail.
It is important to note that some of these features already exist in PHP versions below 5.3, or at least to be implemented in less than 5.3 versions. When this article mentions PHP 5.3, it is not a strictly responsible PHP runtime version. Instead, it means that code libraries and projects use PHP 5.3 as the lowest version, but at the same time all the best practices that emerge during the new development phase. This stage of development highlights a number of "2.0" attempts by specific projects such as the Zend Framework, Symfony, doctrine, and PEAR.
Background
PHP 5.2 has only one exception class Exception. According to the Zend framework/pear development standard, this class is the base class for all the exception classes in your library. If you create a library called MyCompany, all of the code files in the library will begin with Mycompany_, according to the Zend Framework/pear standard. If you want to create your own exception base class for the library: Mycompany_exception, then inherit the Exception with the class, and then inherit and throw the exception class by the component (component). For example, if you have a component Mycompany_foo, you can create an exception base class mycompany_foo_exception that is used inside the component. These exceptions can be captured by capturing Mycompany_foo_exception,mycompany_exception or Exception code. For other code in the library that uses the component, this is a three-level exception (or more, depending on how many layers of the mycompany_foo_exception's subclasses), and they can handle the exceptions as they need to.
In PhP5, the base exception class already supports nested attributes. What is nesting? Nesting is the ability to catch special exceptions, or to capture a new exception object that is created by referencing the original exception. This will allow the caller attribute to be represented on two exception classes that appear in a more exposed type of overhead library, and certainly in the exception class with the original exception behavior.
Why are these features useful? In general, exceptions that throw their own types by using other code are the most efficient code. The code might be a code that uses a Third-party code base encapsulated by the adapter pattern to provide some of the more adaptable functions, or a simple code that uses some PHP extensions to throw exceptions.
For example, in component zend_db, it uses the adapter pattern to encapsulate a specific PHP extension to create a database abstraction layer. In one adapter, zend_db encapsulates PDO, and PDO throws its own exception pdoexception, zend_db need to catch these PDO-specific exceptions and let them be thrown back with predictable and type-known zend_db_exception. This gives the developer the assurance that zend_db will always throw zend_db_exception types of exceptions (so they can be captured), and that they can also access the pdoexception that was first thrown when needed.
The following example shows how a fictitious database adapter might implement an embedded exception:
Class Mycompany_database
{
/**
* @var PDO Object Setup during construction
* * Protected
$_ Pdoresource = null;
/**
* @throws mycompany_database_exception
* @return int
/Public Function executequery ($sql)
{
try {
$numRows = $this->_pdoresource->exec ($sql);
} catch (Pdoexception $e) {
throw New Mycompany_database_exception (' Query was unexecutable ', null, $e);
}
return $numRows;
}
In order to use an embedded exception, you have to invoke the GetPrevious () method of the caught exception:
$sql and $connectionParameters assumed
try {
$db = new Mycompany_database (' PDO ', $connectionParams);
$db->executequery ($sql);
} catch (Mycompany_database_exception $e) {
echo ' General Error: '. $e->getmessage (). "\ n";
$pdoException = $e->getprevious ();
Echo ' PDO specific error: '. $pdoException->getmessage (). "\ n";
}
Most of the most recently implemented PHP extensions have OO (object-oriented) interfaces. As a result, these APIs tend to throw exceptions rather than error terminations. In PHP, you can throw an exception extension, and a few examples include PDO, DOM, Mysqli, Phar, Soap, and SQLite.
New feature: New Core exception type
In PHP 5.3 Development, we have shown some interesting new exception types. These exceptions already exist in the PHP 5.2.x, but they are now more compelling than the best practice of "reassessing" the exception recently. They are applied in SPL extensions and are listed in the manual (here) as these new exception types are part of the PHP core and are part of SPL, they can be used by anyone running code in PHP 5.3 (and above). While it may seem less important to write code for the application layer, it becomes more important to use these new exception types when we write or use code libraries
So why is the new exception a normal type? Previously, developers tried to give the exception more meaning by putting more content in the exception message reminder. Although this is feasible, it has several drawbacks. One is that you cannot capture a message-based exception. This is a problem, if you know that a group of code is the same exception type and different message corresponding to different exception, the difficulty will be quite large. For example, an authentication class, in pairs of $auth->authenticate (); It throws the same type of exception (assuming an exception), but the different messages correspond to two specific faults: the reason for the failure is that the authentication server cannot achieve but the same exception type prompts for a different validation message. In this case (note that using an exception may not be the best way to handle the authentication response), this will require a string to parse the message to handle the two different situations.
The solution to this problem is obviously to encode the exception in some way so that it can be easily queried when it is necessary to identify how to react to this abnormal environment. The first reaction library is to use the $code property of the exception base class. Another is by creating subclasses or new exception classes that can be thrown and can describe their behavior. The two methods have the same obvious disadvantage. Neither has presented the best example of such a wish. Neither is considered a standard, so every project that attempts to replicate both solutions has a small change, forcing the use of this need to go back to the documentation to understand the specific solution already in the library that was created. Now by using the new type method of SPL, also known as the PHP standard library, developers can be in the same way in their projects, and the new best methods of reusing these projects have emerged.
The second disadvantage is that the use of detailed information makes it difficult for developers with limited English or English ability to understand these anomalies. This may make the developer very slow in trying to understand the meaning of the exception message. Many developers also write articles about exceptions, as there is no single consolidated standard to describe what the exception message describes as a different version of the same number of developers.
So how do I use them, with these silent, dense details?
There are now a total of 13 new exception types in SPL. Two of these can be treated as base classes: logical Exceptions and Run-time exceptions, both of which inherit from the PHP exception class. The remaining methods can logically be split into 3 groups: Dynamic invocation groups, logical groups, and run-time groups.
The dynamic invocation group contains exceptions badfunctioncallexception and Badmethodcallexception, Badmethodcallexception are subclasses of Badfunctioncallexception (Logicexception subclasses), which means that these exceptions can be of direct type (translator: The type of the exception itself, We all know that there are many kinds of anomalies, logicexception, or exception caught (translator: is catch) when should you use these? Typically, you should be in the case of an unhandled __call () method, or the callback cannot be a valid function (simply, when something is not is_callable ()).
For example:
OO variant
class Foo
{public
function __call ($method, $args)
{
switch ($method)
{case ' Dobar ': * */break;
Default:
throw new Badmethodcallexception (' method '. $method. ' is not callable by this object ';
}} Procedural variant
function foo ($bar, $baz) {
$func = ' do '. $baz;
if (!is_callable ($func)) {
throw new badfunctioncallexception (' Function '. $func. ' is not callable ');
}
A direct example of Call_user_func () at the time of __call. This set of exceptions is useful when developing calls to various API dynamic methods, function calls, such as a request that can be sent and interpreted by the SOAP and XML-RPC client/server side.
The second group is the logical (logic) group. This group consists of domainexception, InvalidArgumentException, Lengthexception and Outofrangeexception. These exceptions are also logicexception subclasses, and of course PHP's exception subclass. Use these exceptions when there are arguments for states that are indeterminate, or for the wrong method/function. To better understand this, let's first look at the last set of exceptions
The last group is the Run-time (runtime) group. It is composed of OutOfBoundsException, OverflowException, Rangeexception, Underflowexception and Unexpectedvalueexceptio. These exceptions are also runtimeexception subclasses, and of course PHP's exception subclass. These exceptions (run time groups) are called when the runtime function and method have an exception
How do logical groups and run time groups work together? If you look at the anatomy of an object, it usually happens to be one of the two. First, the object will track and change the state. This means that the object is usually not doing anything. It may pass the structure to it, it may set something through the setter and getter (e.g. $this->foo= ' foo '), or it may refer to other objects. Second, when the object does not track or change the state, it represents an operation-doing what it is supposed to do. This is the object's Run-time (runtime). For example, in the lifetime of an object, it may be created, set something up, then it may be Setfoo ($foo), Setbar ($bar). At these times, any type of logicexception should be raised. In addition, when a method inside an object is called with a parameter, such as $object->dosomething ($someVariation), a logicexception can be thrown when the $somevariation variable is checked in the first few rows. After checking $somevariation, it continues to do its dosomething (), which is considered its "run-time" (runtime), in which the runtimeexcpetions exception may be thrown.
To understand better, let's take a look at how this concept is used in code:
Class Foo
{
protected $number = 0;
protected $bar = null;
Public function __construct ($options)
{
/** This method throws Logicexception exception **/
} public
function Setnumber ($ Number)
{
/** This method throws Logicexception exception **/
} public
function Setbar (Bar $bar)
{
/** This method throws the Logicexception exception **/
} public
function dosomething ($differentNumber)
{
if ($ Differentnumber!= $expectedCondition) {
/** here, throw logicexception exception **/
}
/** * here
, This method throws RuntimeException exception
* *}
}
Now that the concept is understood, what does this mean for users of the code base? The user can determine the exception state of the object at any time, and they can catch (catch) exceptions with the specific type of the exception, such as InvalidArgumentException or lengthexception, or at least logicexception. With this level of precision adjustment, and the variety of types, they can capture the smallest exception with logicexception, but they can also get a better understanding of the actual exception type. The same concept applies to run-time exceptions, which can throw more specific types of exceptions, and can be caught (catch) regardless of specific or neutral types of exceptions. It can provide users with more detailed information and accuracy.
Here is a table about SPL anomalies that you might be interested in
Best practices in class library code
PHP 5.3 brings new exception types and also brings us new best practices. In addition to standardizing certain exceptions (such as: InvalidArgumentException, runtimeexception), it is also important to capture component-level exceptions. In this regard, the ZF2 wiki and PEAR2 wiki are discussed in depth.
In short, in addition to the various best practices mentioned above, we should also use Marker Interface to create a component-level exception base class. By creating a component-level Marker Interface, exceptions that are used within a component can inherit either the SPL exception type or be captured by various code at run time. Let's look at the following code:
Usage of bracket syntax for brevity
namespace Mycompany\component {interface
Exception
{}
class Unexpectedvalueexception
extends \unexpectedvalueexception
implements Exception
{}
class Component
{public
static function dosomething ()
{
if ($somethingExceptionalHappens) {
throw new Unexpectedvalueexception (' Something bad happened ');}}}
If you call the Mycompany\component\component in the above code::D osomething () function, the exception thrown by dosomething () can be captured as the following exception types: PHP Exception, SPL Unexpectedvalueexception, SPL RuntimeException, the mycompany\component\unexpectedvalueexception of the component, or the MyCompany\ of the component Component\exception. This provides a great convenience for capturing exceptions in your class library component. In addition, by analyzing the type of the exception, we can also see the meaning of an exception.