I don't understand why this code:
class MyException extends Exception {};
try {
try {
throw new MyException;
} catch (Exception $e) {
echo "1:";
throw $e;
} catch (MyException $e) {
echo "2:";
throw $e;
}
}
catch (Exception $e) {
echo get_class($e);
}
Returns: 1:MyException.
Isn't it supposed to catch the second one MyException and therefore return 2?
I thought with multiple exceptions it looks for the current try/catch first, but it looks like it catches the exception from the first try? or is it because MyException is empty and it uses Exception instead?
Exception here is a base class for your MyException class. Your $e variable has class MyException, so everything is right. If you make:
echo "1:";
var_dump($e);
throw $e;
you will see that $e is object(MyException). You haven't cast types, you just using polymorphism.
All your objects that have type Exception or it's subtypes will be caught in the 1-st block. Code will be executed in first by order block that can apply the exception.
Catch blocks are processed in the order they appear. Your code for catching MyException will never be called, because all subclasses of Exception are caught in your first catch block.
Related
I'd like a cleaner way to obtain the following functionality, to catch AError and BError in one block:
try
{
/* something */
}
catch( AError, BError $e )
{
handler1( $e )
}
catch( Exception $e )
{
handler2( $e )
}
Is there any way to do this? Or do I have to catch them separately?
AError and Berror have a shared base class, but they also share it with other types that I'd like to fall through to handler2, so I can't just catch the base class.
Update:
As of PHP 7.1, this is available.
The syntax is:
try
{
// Some code...
}
catch(AError | BError $e)
{
// Handle exceptions
}
catch(Exception $e)
{
// Handle the general case
}
Docs: https://www.php.net/manual/en/language.exceptions.php#example-334
RFC: https://wiki.php.net/rfc/multiple-catch
Commit: https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a
For PHP before 7.1:
Despite what these other answers say, you can catch AError and BError in the same block (it is somewhat easier if you are the one defining the exceptions). Even given that there are exceptions you want to "fall through", you should still be able to define a hierarchy to match your needs.
abstract class MyExceptions extends Exception {}
abstract class LetterError extends MyExceptions {}
class AError extends LetterError {}
class BError extends LetterError {}
Then:
catch(LetterError $e){
//voodoo
}
As you can see here and here, even the SPL default exceptions have a hierarchy you can leverage. Additionally, as stated in the PHP Manual:
When an exception is thrown, code following the statement will not be
executed, and PHP will attempt to find the first matching catch block.
This means you could also have
class CError extends LetterError {}
which you need to handle differently than AError or BError, so your catch statement would look like this:
catch(CError $e){
//voodoo
}
catch(LetterError $e){
//voodoo
}
If you had the case where there were twenty or more exceptions that legitimately belonged under the same superclass, and you needed to handle five (or whatever large-ish group) of them one way and the rest the other, you can STILL do this.
interface Group1 {}
class AError extends LetterError implements Group1 {}
class BError extends LetterError implements Group1 {}
And then:
catch (Group1 $e) {}
Using OOP when it comes to exceptions is very powerful. Using things like get_class or instanceof are hacks, and should be avoided if possible.
Another solution I would like to add is putting the exception handling functionality in its own method.
You could have
function handleExceptionMethod1(Exception $e)
{
//voodoo
}
function handleExceptionMethod2(Exception $e)
{
//voodoo
}
Assuming there is absolutely no way you can control exception class hierarchies or interfaces (and there almost always will be a way), you can do the following:
try
{
stuff()
}
catch(ExceptionA $e)
{
$this->handleExceptionMethod1($e);
}
catch(ExceptionB $e)
{
$this->handleExceptionMethod1($e);
}
catch(ExceptionC $e)
{
$this->handleExceptionMethod1($e);
}
catch(Exception $e)
{
$this->handleExceptionMethod2($e);
}
In this way, you are still have a only single code location you have to modify if your exception handling mechanism needs to change, and you are working within the general constructs of OOP.
In PHP >= 7.1 this is possible. See this answer.
If you can modify the exceptions, use this answer.
If you can't, you could try catching all with Exception and then check which exception was thrown with instanceof.
try
{
/* something */
}
catch( Exception $e )
{
if ($e instanceof AError OR $e instanceof BError) {
// It's either an A or B exception.
} else {
// Keep throwing it.
throw $e;
}
}
But it would probably be better to use multiple catch blocks as described in aforementioned answer.
try
{
/* something */
}
catch( AError $e )
{
handler1( $e );
}
catch ( BError $b )
{
handler2( $e );
}
Coming in PHP 7.1 is the ability to catch multiple types.
So that this:
<?php
try {
/* ... */
} catch (FirstException $ex) {
$this->manageException($ex);
} catch (SecondException $ex) {
$this->manageException($ex);
}
?>
and
<?php
try {
} catch (FirstException | SecondException $ex) {
$this->manageException($ex);
}
?>
are functionally equivalent.
As of PHP 7.1,
catch( AError | BError $e )
{
handler1( $e )
}
interestingly, you can also:
catch( AError | BError $e )
{
handler1( $e )
} catch (CError $e){
handler2($e);
} catch(Exception $e){
handler3($e);
}
and in earlier versions of PHP:
catch(Exception $ex){
if($ex instanceof AError || $ex instanceof BError){
//handle AError and BError
} elseif($ex instanceof CError){
//handle CError
} else {
throw $ex; // an unknown exception occurred, throw it further
}
}
This article covers the question electrictoolbox.com/php-catch-multiple-exception-types. Content of the post copied directly from the article:
Example exceptions
Here's some example exceptions that have been defined for the purposes of this example:
class FooException extends Exception
{
public function __construct($message = null, $code = 0)
{
// do something
}
}
class BarException extends Exception
{
public function __construct($message = null, $code = 0)
{
// do something
}
}
class BazException extends Exception
{
public function __construct($message = null, $code = 0)
{
// do something
}
}
Handling multiple exceptions
It's very simple - there can be a catch block for each exception type that can be thrown:
try
{
// some code that might trigger a Foo/Bar/Baz/Exception
}
catch(FooException $e)
{
// we caught a foo exception
}
catch(BarException $e)
{
// we caught a bar exception
}
catch(BazException $e)
{
// we caught a baz exception
}
catch(Exception $e)
{
// we caught a normal exception
// or an exception that wasn't handled by any of the above
}
If an exception is thrown that is not handled by any of the other catch statements it will be handled by the catch(Exception $e) block. It does not necessarily have to be the last one.
As an extension to the accepted answer, you could switch the type of Exception resulting in a pattern that is somewhat like the original example:
try {
// Try something
} catch (Exception $e) {
switch (get_class($e)) {
case 'AError':
case 'BError':
// Handle A or B
break;
case 'CError':
// Handle C
break;
case default:
// Rethrow the Exception
throw $e;
}
}
Here's a reasonable alternative if you don't have control over defining the exceptions. Use the name of the exception variable to categorize the exceptions when they are caught. Then check for the exception variable after the try/catch block.
$ABError = null;
try {
// something
} catch (AError $ABError) { // let the exception fall through
} catch (BError $ABError) { // let the exception fall through
} catch (Exception $e) {
handler2($e);
}
if ($ABError) {
handler1($ABError);
}
This somewhat odd looking approach is probably only worth it if there is a lot of duplication between catch block implementations.
Besides fall-through, it's also possible to step over by using goto.
It's very useful if you want to see the world burn.
<?php
class A_Error extends Exception {}
class B_Error extends Exception {}
class C_Error extends Exception {}
try {
throw new A_Error();
}
catch (A_Error $e) { goto abc; }
catch (B_Error $e) { goto abc; }
catch (C_Error $e) {
abc:
var_dump(get_class($e));
echo "Gotta Catch 'Em All\n";
}
3v4l.org
As of PHP 8.0 you can use even cleaner way to catch your exceptions when you don't need to output the content of the error (from variable $e). However you must replace default Exception with Throwable.
try {
/* something */
} catch (AError | BError) {
handler1()
} catch (Throwable) {
handler2()
}
Hmm, there are many solution written for php version lower than 7.1.
Here is an other simple one for those who doesn't want catch all exception and can't make common interfaces:
<?php
$ex = NULL
try {
/* ... */
} catch (FirstException $ex) {
// just do nothing here
} catch (SecondException $ex) {
// just do nothing here
}
if ($ex !== NULL) {
// handle those exceptions here!
}
?>
Another option not listed here is to use the code attribute of an exception, so you can do something like this:
try {
if (1 === $foo) {
throw new Exception(sprintf('Invalid foo: %s', serialize($foo)), 1);
}
if (2 === $bar) {
throw new Exception(sprintf('Invalid bar: %s', serialize($foo)), 2);
}
} catch (Exception $e) {
switch ($e->getCode()) {
case 1:
// Special handling for case 1
break;
case 2:
// Special handling for case 2
break;
default:
// Special handling for all other cases
}
}
A great way is to use set_exception_handler.
Warning!!! with PHP 7, you might get a white screen of death for fatal errors. For example, if you call a method on a non-object you would normally get Fatal error: Call to a member function your_method() on null and you would expect to see this if error reporting is on.
The above error will NOT be caught with catch(Exception $e).
The above error will NOT trigger any custom error handler set by set_error_handler.
You must use catch(Error $e){ } to catch errors in PHP7. .
This could help:
class ErrorHandler{
public static function excep_handler($e)
{
print_r($e);
}
}
set_exception_handler(array('ErrorHandler','excep_handler'));
I have a custom error handlers:
set_error_handler('API_Error_Handler');
register_shutdown_function('Fatal_Error_Handler'); // This one calls API_Error_Handler eventually
In the following example, both catch{} section AND API_Error_Handler are executed.
try{
// Exception raised here
} catch(Exception $e){
// No error reporting needed, do something else
}
I want ONLY catch{} to execute. How do I do that? Maybe determine within API_Error_Handler whether exception is already caught by try-catch? Or are there other approaches available?
Example code:
set_error_handler(function() {
echo "Error is handled by custom error handler. <br>";
});
try{
new SoapClient('http://bad.address/wsdl');
} catch(Exception $e){
echo "Error is caught. <br>";
}
I think the best way will be to create an Exception class by your self that extends Exception:
class MyCustomException extends \Exception {}
and throw this where you need it. Then change
} catch (Exception $e)
to
} catch (MyCustomException $e)
and you should only get your custom exception catched
I've setup the ZendSkeletonApplication with ZF 2.0.3 and I am unable to catch exceptions in my controllers. For instance if I put the below piece of code in module/Application/src/Application/Controller/IndexController.php:
public function indexAction() {
echo "BEFORE\n";
try {
throw new \Exception("My exception");
} catch (Exception $e) {
echo "Caught exception $e\n";
exit;
}
and access the page I get:
BEFORE
An error occurred
An error occurred during execution; please try again later.
Additional information:
Exception
File:
module/Application/src/Application/Controller/IndexController.php:25
Message:
My exception
the ViewModel kicks in and displays the exception, effectively preventing me from catching it.
How can I catch exceptions in ZF2 controllers?
You are throwing PHP's generic Exception
throw new \Exception("My exception");
but you catch the Exception from the current namespace
} catch (Exception $e) {
Assuming your controller is in Application\Controller, you either have to declare
use \Exception;
above your class to import the global Exception into the current namespace or
} catch (\Exception $e) {
to catch PHP's global Exception.
I'd like a cleaner way to obtain the following functionality, to catch AError and BError in one block:
try
{
/* something */
}
catch( AError, BError $e )
{
handler1( $e )
}
catch( Exception $e )
{
handler2( $e )
}
Is there any way to do this? Or do I have to catch them separately?
AError and Berror have a shared base class, but they also share it with other types that I'd like to fall through to handler2, so I can't just catch the base class.
Update:
As of PHP 7.1, this is available.
The syntax is:
try
{
// Some code...
}
catch(AError | BError $e)
{
// Handle exceptions
}
catch(Exception $e)
{
// Handle the general case
}
Docs: https://www.php.net/manual/en/language.exceptions.php#example-334
RFC: https://wiki.php.net/rfc/multiple-catch
Commit: https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a
For PHP before 7.1:
Despite what these other answers say, you can catch AError and BError in the same block (it is somewhat easier if you are the one defining the exceptions). Even given that there are exceptions you want to "fall through", you should still be able to define a hierarchy to match your needs.
abstract class MyExceptions extends Exception {}
abstract class LetterError extends MyExceptions {}
class AError extends LetterError {}
class BError extends LetterError {}
Then:
catch(LetterError $e){
//voodoo
}
As you can see here and here, even the SPL default exceptions have a hierarchy you can leverage. Additionally, as stated in the PHP Manual:
When an exception is thrown, code following the statement will not be
executed, and PHP will attempt to find the first matching catch block.
This means you could also have
class CError extends LetterError {}
which you need to handle differently than AError or BError, so your catch statement would look like this:
catch(CError $e){
//voodoo
}
catch(LetterError $e){
//voodoo
}
If you had the case where there were twenty or more exceptions that legitimately belonged under the same superclass, and you needed to handle five (or whatever large-ish group) of them one way and the rest the other, you can STILL do this.
interface Group1 {}
class AError extends LetterError implements Group1 {}
class BError extends LetterError implements Group1 {}
And then:
catch (Group1 $e) {}
Using OOP when it comes to exceptions is very powerful. Using things like get_class or instanceof are hacks, and should be avoided if possible.
Another solution I would like to add is putting the exception handling functionality in its own method.
You could have
function handleExceptionMethod1(Exception $e)
{
//voodoo
}
function handleExceptionMethod2(Exception $e)
{
//voodoo
}
Assuming there is absolutely no way you can control exception class hierarchies or interfaces (and there almost always will be a way), you can do the following:
try
{
stuff()
}
catch(ExceptionA $e)
{
$this->handleExceptionMethod1($e);
}
catch(ExceptionB $e)
{
$this->handleExceptionMethod1($e);
}
catch(ExceptionC $e)
{
$this->handleExceptionMethod1($e);
}
catch(Exception $e)
{
$this->handleExceptionMethod2($e);
}
In this way, you are still have a only single code location you have to modify if your exception handling mechanism needs to change, and you are working within the general constructs of OOP.
In PHP >= 7.1 this is possible. See this answer.
If you can modify the exceptions, use this answer.
If you can't, you could try catching all with Exception and then check which exception was thrown with instanceof.
try
{
/* something */
}
catch( Exception $e )
{
if ($e instanceof AError OR $e instanceof BError) {
// It's either an A or B exception.
} else {
// Keep throwing it.
throw $e;
}
}
But it would probably be better to use multiple catch blocks as described in aforementioned answer.
try
{
/* something */
}
catch( AError $e )
{
handler1( $e );
}
catch ( BError $b )
{
handler2( $e );
}
Coming in PHP 7.1 is the ability to catch multiple types.
So that this:
<?php
try {
/* ... */
} catch (FirstException $ex) {
$this->manageException($ex);
} catch (SecondException $ex) {
$this->manageException($ex);
}
?>
and
<?php
try {
} catch (FirstException | SecondException $ex) {
$this->manageException($ex);
}
?>
are functionally equivalent.
As of PHP 7.1,
catch( AError | BError $e )
{
handler1( $e )
}
interestingly, you can also:
catch( AError | BError $e )
{
handler1( $e )
} catch (CError $e){
handler2($e);
} catch(Exception $e){
handler3($e);
}
and in earlier versions of PHP:
catch(Exception $ex){
if($ex instanceof AError || $ex instanceof BError){
//handle AError and BError
} elseif($ex instanceof CError){
//handle CError
} else {
throw $ex; // an unknown exception occurred, throw it further
}
}
This article covers the question electrictoolbox.com/php-catch-multiple-exception-types. Content of the post copied directly from the article:
Example exceptions
Here's some example exceptions that have been defined for the purposes of this example:
class FooException extends Exception
{
public function __construct($message = null, $code = 0)
{
// do something
}
}
class BarException extends Exception
{
public function __construct($message = null, $code = 0)
{
// do something
}
}
class BazException extends Exception
{
public function __construct($message = null, $code = 0)
{
// do something
}
}
Handling multiple exceptions
It's very simple - there can be a catch block for each exception type that can be thrown:
try
{
// some code that might trigger a Foo/Bar/Baz/Exception
}
catch(FooException $e)
{
// we caught a foo exception
}
catch(BarException $e)
{
// we caught a bar exception
}
catch(BazException $e)
{
// we caught a baz exception
}
catch(Exception $e)
{
// we caught a normal exception
// or an exception that wasn't handled by any of the above
}
If an exception is thrown that is not handled by any of the other catch statements it will be handled by the catch(Exception $e) block. It does not necessarily have to be the last one.
As an extension to the accepted answer, you could switch the type of Exception resulting in a pattern that is somewhat like the original example:
try {
// Try something
} catch (Exception $e) {
switch (get_class($e)) {
case 'AError':
case 'BError':
// Handle A or B
break;
case 'CError':
// Handle C
break;
case default:
// Rethrow the Exception
throw $e;
}
}
Here's a reasonable alternative if you don't have control over defining the exceptions. Use the name of the exception variable to categorize the exceptions when they are caught. Then check for the exception variable after the try/catch block.
$ABError = null;
try {
// something
} catch (AError $ABError) { // let the exception fall through
} catch (BError $ABError) { // let the exception fall through
} catch (Exception $e) {
handler2($e);
}
if ($ABError) {
handler1($ABError);
}
This somewhat odd looking approach is probably only worth it if there is a lot of duplication between catch block implementations.
Besides fall-through, it's also possible to step over by using goto.
It's very useful if you want to see the world burn.
<?php
class A_Error extends Exception {}
class B_Error extends Exception {}
class C_Error extends Exception {}
try {
throw new A_Error();
}
catch (A_Error $e) { goto abc; }
catch (B_Error $e) { goto abc; }
catch (C_Error $e) {
abc:
var_dump(get_class($e));
echo "Gotta Catch 'Em All\n";
}
3v4l.org
As of PHP 8.0 you can use even cleaner way to catch your exceptions when you don't need to output the content of the error (from variable $e). However you must replace default Exception with Throwable.
try {
/* something */
} catch (AError | BError) {
handler1()
} catch (Throwable) {
handler2()
}
Hmm, there are many solution written for php version lower than 7.1.
Here is an other simple one for those who doesn't want catch all exception and can't make common interfaces:
<?php
$ex = NULL
try {
/* ... */
} catch (FirstException $ex) {
// just do nothing here
} catch (SecondException $ex) {
// just do nothing here
}
if ($ex !== NULL) {
// handle those exceptions here!
}
?>
Another option not listed here is to use the code attribute of an exception, so you can do something like this:
try {
if (1 === $foo) {
throw new Exception(sprintf('Invalid foo: %s', serialize($foo)), 1);
}
if (2 === $bar) {
throw new Exception(sprintf('Invalid bar: %s', serialize($foo)), 2);
}
} catch (Exception $e) {
switch ($e->getCode()) {
case 1:
// Special handling for case 1
break;
case 2:
// Special handling for case 2
break;
default:
// Special handling for all other cases
}
}
A great way is to use set_exception_handler.
Warning!!! with PHP 7, you might get a white screen of death for fatal errors. For example, if you call a method on a non-object you would normally get Fatal error: Call to a member function your_method() on null and you would expect to see this if error reporting is on.
The above error will NOT be caught with catch(Exception $e).
The above error will NOT trigger any custom error handler set by set_error_handler.
You must use catch(Error $e){ } to catch errors in PHP7. .
This could help:
class ErrorHandler{
public static function excep_handler($e)
{
print_r($e);
}
}
set_exception_handler(array('ErrorHandler','excep_handler'));
I been searching for this and I just seem to run into the same articles, in this code:
try
{
//some code
}
catch(Exception $e){
throw $e;
}
Where does $e gets stored or how the webmaster see it? Should I look for a special function?
An Exception object (in this case, $e) thrown from inside a catch{} block will be caught by the next highest try{} catch{} block.
Here's a silly example:
try {
try {
throw new Exception("This is thrown from the inner exception handler.");
}catch(Exception $e) {
throw $e;
}
}catch(Exception $e) {
die("I'm the outer exception handler (" . $e->getMessage() . ")<br />");
}
The output of the above is
I'm the outer exception handler (This is thrown from the inner exception handler.)
One nice thing is that Exception implements __toString() and outputs a call stack trace.
So sometimes in low-level Exceptions that I know I'm gonna want to see how I got to, in the catch() I simply do
error_log($e);
$e is an instance of Exception or any other class that extended from Exception. Those objects have some specific attributes and methods in common (inherited from the Exception class) you can use. See the chapter about exceptions and the Exception member list for more details.
I'm assuming your using some sort of third party code/library with this code in it that is throwing the exception into your code. You simply have to be ready for an exception to be thrown to catch it, then you can log it/display it however you want.
try {
$Library->procedure();
catch(Exception $e) {
echo $e->getMessage(); //would echo the exception message.
}
For more information read the PHP manual's entry on Exceptions.
The lines:
catch(Exception $e){
throw $e;
}
Don\t make sense. When you catch an Exception you're suppose to do something with the exception like:
catch(Exception $e){
error_log($e->getMessage());
die('An error has occurred');
}
But in your case the Exception is thrown directly to an outer try-block which would already happen.
If you change your code to:
//some code
Would create the exact same behaviour.