How to implement exception chaining in PHP - php

Constructor for PHP's exception has third parameter, documentation says:
$previous: The previous exception used for the exception chaining.
But I can't make it work. My code looks like this:
try
{
throw new Exception('Exception 1', 1001);
}
catch (Exception $ex)
{
throw new Exception('Exception 2', 1002, $ex);
}
I expect Exception 2 to be thrown and I expect that it will have Exception 1 attached. But all I get is:
Fatal error: Wrong parameters for Exception([string $exception [, long $code ]]) in ...
What am I doing wrong?

The third parameter requires version 5.3.0.

Before 5.3 you can just create your own custom exception class. It is also recommended to do this, I mean if I catch (Exception $e) then my code must handle all exceptions rather then just the one I'm wanting, code explains it better.
class MyException extends Exception
{
protected $PreviousException;
public function __construct( $message, $code = null, $previousException = null )
{
parent::__construct( $message, $code );
$this->PreviousException = $previousException;
}
}
class IOException extends MyException { }
try
{
$fh = #fopen("bash.txt", "w");
if ( $fh === false)
throw new IOException('File open failed for file `bash.txt`');
}
catch (IOException $e)
{
// Only responsible for I/O related errors
}

I get:
Uncaught exception 'Exception' with message 'Exception 1' ...
Next exception 'Exception' with message 'Exception 2' in ...
You using php > 5.3 ?

Related

Laravel exception not catching

I'm trying to do a very basic exception try catch, but it doesn't catch.
$id =0;
try {
$question = $this->model->find($id); // will not find anything since $id = 0
$question->delete(); // throw an exception
return true;
} catch (\Exception $e) {
dd ('hello'); // should end up here, but no?!?!?
} catch (FatalThrowableError $f) {
echo ("fatal"); // or here... but no.
}
but the catch doesn't "catch". I get an Fatal error in the browser saying that delete was called on a null object. But that's exactly what I was trying to do: do a delete on a null object (id = 0 is not in the DB), to test the exception.
I have tried
use Symfony\Component\Debug\Exception;
use Symfony\Component\Debug\Exception\FatalThrowableError;
or simply
Exception;
FatalThrowableError;
Also, having the \Exception $e or Exception $e (with or without ) doesn't change anything.
Note that if I add a line like $foo = 4/0 I get into the Exception section (dd (hello)).
in .env APP_DEBUG=true, APP_LOG_LEVEL=debug
I'm on Laravel 5.5 using PHP 7.0.10 on windows 7.
http://php.net/manual/en/language.errors.php7.php
As the Error hierarchy does not inherit from Exception, code that uses
catch (Exception $e) { ... } blocks to handle uncaught exceptions in
PHP 5 will find that these Errors are not caught by these blocks.
Either a catch (Error $e) { ... } block or a set_exception_handler()
handler is required.
You can, additionally, catch (\Throwable $e) {} to account for both Error and Exception types.

Can't catch exceptions in laravel

I have the following situation:
try {
DB::beginTransaction();
$task = new Task();
$task->setTracker("");
//thrown \Symfony\Component\Debug\Exception\FatalThrowableError
DB::commit();
}catch (\Exception $e){
DB::rollBack();
Log::error($e);
//throw $e;
}
I am not entering to the catch area.
Any idea why?
update
This is the error thrown:
[Symfony\Component\Debug\Exception\FatalThrowableError]
Type error: Argument 1 passed to App\Models\Task::setTracker() must be an instance of Carbon\Carbon, integer given, called in /var/www/app/Services/ShareLogic.php on line 60
and will not be catched
Thanks
Catching Throwable did the trick.
Have no idea why?
Anyone does?
It does not catch the exception because you are trying to catch \Exception which Symfony\Component\Debug\Exception\FatalThrowableError does not extend.
Instead try to catch the actual exception by importing it..
use Symfony\Component\Debug\Exception\FatalThrowableError;
And then you can do..
try {
//
} catch(FatalThrowableError e) {
//
}
Edit
Ok, so in addition to the above solution it seems PHP 7+ handles error a bit differently than PHP 5. So try this..
try {
//
} catch(Error $e) {
// This should work
} catch(Throwable $e) {
// This should work as well
}
Symfony's Debug component is much more sophisticated in order to log and report all kinds of errors but take look at this simple example (php 7.1.x):
<?php
class MyUncatchableError extends Exception {}
function myExceptionHandler($e) {
throw new MyUncatchableError('BANG: '.$e->getMessage());
}
set_exception_handler('myExceptionHandler');
$foo = true;
try {
$foo->modify();
} catch (Exception $e) {
echo 'nope';
} catch (MyUncatchableError $e) {
echo 'nope2';
}
What will be the outcome? Well:
Fatal error: Uncaught MyUncatchableError: BANG: Call to a member function modify() on boolean in /in/WJErU:6
Stack trace:
0 [internal function]: myExceptionHandler(Object(Error))
1 {main}
thrown in /in/WJErU on line 6
and you can't catch that exception because you should catch the original.. throwable here, which is Error for this kind of "error". You can catch it by catching "Error" class. And with PHP7 hierarchy it implements Throwable interface, that's why you can't catch it using Exception (because while Exception implements Throwable, Error is no an Exception - see: http://php.net/manual/en/language.errors.php7.php).
And this is true for PHP7+ because with 5.* there was no Throwable nor Error, and doing $foo->modify(); would just stop the script and return a Fatal Error. You can make your own error handler (set_error_handler) and throw an exception there (and Debug component does that for php 5.*) but this method does not work for Fatal Errors. Instead Debug component hooks into script shutdown and reads last error and throws FatalErrorException.
This description may not be completely accurate as I have't dug deeply into Symfony but you can get the idea here.

Can I use throw without any message?

Here is my code:
try {
if ( condition 1 ) {
throw;
} else {
// do something
}
// some code here
if ( condition 2 ){
throw;
}
} catch (Exception $e) {
echo "something is wrong";
}
As you see, my catch block has its own error message, And that message is a constant. So really I don't need to pass a message when I use throw like this:
throw new Exception('error message');
Well can I use throw without anything? I just need to jump into catch block.
Honestly writing an useless error message is annoying for me.
As you know my current code has a syntax error: (it referring to throw;)
Parse error: syntax error, unexpected ';' in {path}
message parameter is optional in the Exception constructor. So if you don't have/want to put - just don't:
throw new Exception;
But you still must throw an instance of the Exception class (or a class that extends it), since it is a part of the php language syntax.
If you want all your exceptions to have the same message, you can extend it and define the message in your class:
class AmbiguousException extends Exception {
public function __construct($message = 'Something is wrong.', $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
}
Then:
throw new AmbiguousException();
You can use the below throw everytime you need.
throw new Exception();
and catch will remain same as your code.
As stated in the PHP manual:
The thrown object must be an instance of the Exception class or a subclass of Exception. Trying to throw an object that is not will result in a PHP Fatal Error.
You can throw an exception without any message:
throw new Exception();
Perhaps something to help you from duplicating the same exception is as follows:
$e = new Exception('something is wrong');
try {
throw $e;
} catch (Exception $ex) {
echo $ex->getMessage();
}
You can create an instance with default message and then throw that instance.
$Exception = new Exception("some error message!");
try {
throw $Exception;
} catch (Exception $ex) {
var_dump($ex);
}
You cannot use the throw keyword on its own. However, you can use throw new Exception(); without specify the $message parameter, because it'll just fallback to the default message. Check out the Exceptions section in the PHP manual: http://php.net/manual/en/language.exceptions.extending.php

PHP exception handler and shutdown function

How do i catch (custom)exceptions (with custom exception handler) that i have thrown in custom shutdown function ? I am not using any framework.
Example:
register_shutdown_function( 'shutdownFunction');
set_exception_handler( 'exceptionHandler');
function exceptionHandler(Exception $exception)
{
// handle and log exception for later debugging...
}
function shutdownFunction()
{
// something is not going right...
if (someVariable != someValue)
throw new RuntimeException('blah...'); // WILL NOT be caught by exception handler
}
// somewhere else in the code...
throw new Exception('something...'); // WILL be caught by exception handler (but not in shutdown function)
The script is using exceptions to communicate that it encountered an error during execution ie. unexpected variable passed to function, database failed to insert row etc...
You simply cannot do this in php.
The register_shutdown_function callback is the last thing that happens in your PHP application. Trying to throw an exception in there will not do anything but invoke a standard php handler. There isn't much to be found on the web regarding these inner workings.
However, I created my own solution for directing it to a single function.
set_exception_handler and register_shutdown_functionare very different functions:
set_exception_handler receives a single argument Exception
register_shutdown_function receives no arguments by default
I've made it so that the set_exception_handler (which receives $exception as argument) sets a property which I can use in the register_shutdown_function.
$lastException = null;
set_exception_handler(function ($e) use (&$lastException) {
$lastException = $e;
});
register_shutdown_function(function() use(&$lastException) {
if($error = error_get_last()) {
$lastException = new \ErrorException($error['message'], $error['type'], 1, $error['file'], $error['line']);
}
if($lastException) {
if (APPLICATION_ENV === 'production') {
Sentry\captureException($lastException);
} else {
var_dump($lastException);
}
}
});
I have no clue if this is a good way to solve the issue, but it allowed me to catch require unexisting_phpfile1389.php errors (Fatal) and regular throw \Exception()s in the same function.
Trying to throw an exception inside the shutdown handler will result in the following exception (how ironic):
( ! ) Fatal error: Uncaught Error: Can only throw objects in
C:...\index.php on line 34
( ! ) Error: Can only throw objects in
C:...\index.php on line 34
You can just wrap the body of your shutdownFunction with
function shutdownFunction()
try {
...
} catch (\Exception $e) {
// do something
}
}
and you will catch all exceptions becase Exception is the base class for all of them
It's quite simple:
function exception_handler (Exception $e) {
if ($e instanceof DBException)
error_handler (['query' => $e->getQuery ()]); // Your actions with your custom Exception object
}
function error_handler ($error) {
if (isset ($error['query']))
echo $error['query'];
else
// Another errors
}
set_error_handler ('error_handler', E_ALL);
set_exception_handler ('exception_handler');

How to catch an exception from another class method PHP

I'm having trouble catching an exception in PHP
Here's my code.
try {
require $this->get_file_name($action);
}
catch (Exception $e) {
//do something//
}
and the method being called
private function get_file_name($action) {
$file = '../private/actions/actions_'.$this->group.'.php';
if (file_exists($file) === false) {
throw new Exception('The file for this '.$action.' was not found.');
}
else {
return $file;
}
}
Resulting in:
Fatal error: Uncaught exception 'Exception' with message $action was not found.'
Exception: The file for this $action was not found.
However If I put a try-catch block inside of the function and call the function, I'm able to catch the exception no problem.
What am I doing wrong?
If you are catching the Exception inside a namespace, make sure that you fall back to the global namespace:
...
}(catch \Exception $e) {
...
}...
You can also have a look at the following resources:
Why isn't my Exception being caught by catch?
http://php.net/manual/en/language.exceptions.php, top note by user zmunoz
I can't see all of the class body but If You want to use method out of the class it should be Public not Private.
Try to check if file You trying to get exists:
var_dump($file = '../private/actions/actions_'.$this->group.'.php');
IMO there is no file in this path

Categories