Let's say I have a class with a method like this:
/*
*
* Loads the user from username.
*
* @param string $username The username
*
* @return UserInterface
*
* @throws userNotFoundException if the user is not found
*/
public function getUser($username)
{
// someFunction return an UserInterface class if found, or null if not.
$user = someFunction('SELECT ....', $username);
if ($user === null) {
throw new userNotFoundException();
}
return $user
}
Now let's say that someFunction
could throw a InvalidArgumentException
/ RuntimeException
/ PDOException
for XYZ reasons. What should I do? And what not?
Add all the possible exceptions that could throw someFunction
in php-docs.
/*
*
* Loads the user from username.
*
* @param string $username The username
*
* @return UserInterface
*
* @throws userNotFoundException if the user is not found
* @throws InvalidArgumentException
* @throws ...
*/
Add a try-catch block to ensure that the method should throw exceptions ONLY documented
/*
*
* Loads the user from username.
*
* @param string $username The username
*
* @return UserInterface
*
* @throws userNotFoundException if the user is not found
* @throws RuntimeException
*/
public function getUser($username)
{
try {
$user = someFunction('SELECT ....', $username);
} catch (Exception $e) {
throw new RuntimeException();
}
if ($user === null) {
throw new userNotFoundException();
}
return $user
}
Don't do anything.
Exception handling is a powerful mechanism of PHP, which is used to handle runtime errors (runtime errors are called exceptions). So that the normal flow of the application can be maintained. The main purpose of using exception handling is to maintain the normal execution of the application.
The following keywords are used for PHP exception handling. Try: The try block contains the code that may potentially throw an exception. All of the code within the try block is executed until an exception is potentially thrown. Throw: The throw keyword is used to signal the occurrence of a PHP exception.
Because exceptions are objects, they all extend a built-in Exception class (see Throwing Exceptions in PHP), which means that catching every PHP exception thrown is as simple as type-hinting the global exception object, which is indicated by adding a backslash in front: try { // ... } catch ( \Exception $e ) { // ... }
Personally I would consider treating @throws
similar to Java's checked exceptions
The way this works in Java is that basically exceptions that inherit from RuntimeException can be thrown and don't have to be handled. Any other types of exceptions must have a try-catch block to handle them. This handling code must be in the caller.
Basically in PHP kinda like this:
When a method has a @throws
annotation, you have to add code to handle its exceptions.
Any exceptions that don't get mentioned are optional for handling in the calling code.
Now, I don't 100% follow this principle myself. The whole handling exceptions thing is sort of up to the programmer's preference, but this is just some thoughts on how I think it could be handled in a reasonable fashion.
With regards to documentation, if a function explicitly throws an exception then it should be included in the function's documentation. Thus, for each throw
statement, there should be a corresponding @throws
in the PHP documentation.
With regards to handling, if there are some operations that should be executed when the exception is thrown then catch it. Otherwise, let it bubble up -- provided there is a catch
statement going to handle it later.
A few years later, I have changed to the opinion that one should only let an exception "bubble up" unmodified when the exception is still relevant to the module's level of abstraction. Catch and re-throw strategies should be employed to make the exception more meaningful. It should also make error handling more secure by avoiding unnecessary disclosure of information about modules underlying the abstraction.
/**
* @throws UserNotFoundException
*/
public function getUser($username)
{
try {
$user = someFunction('SELECT ....', $username);
} catch (DatabaseException $dbe) {
/* Re-throw since a database exception may no longer be
* meaningful to the caller.
*/
throw new UserNotFoundException();
}
return $user
}
From a documentation maintenance point of view, I would only be adding the @throw lines for exceptions that are specifically thrown otherwise you will quickly get your documentation out of date.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With