In my PHP project,Observer Pattern used everywhere,like:
foreach ($this->_aObserver as $observer)
{
$observer->vOnUpdate();
}
But if one observer shutdown because of Fatal Error or Uncaught Exception, the rest of observers can not be triggered.
So any idea to solve this issue?
Assuming you're implementing the observer pattern yourself and by observer shutting down you mean an exception is thrown you can wrap the method call in a try...catch. See http://php.net/manual/en/language.exceptions.php
foreach ($this->_aObserver as $observer)
{
try {
$observer->vOnUpdate();
} catch (\Exception $exception) {
// do something with the error or just move on?
}
}
For the fatal error catching you'll have to create a function to catch the fatal error and basically ignore it. Which this isn't recommended, fatal errors are not meant to be recovered from. See: http://php.net/manual/en/function.register-shutdown-function.php
Try to use try catch
foreach ($this->_aObserver as $observer)
{
try {
$observer->vOnUpdate();
} catch(\Exception $e) {
// log message
}
}
You can check if the method exists and then call itif yes.
foreach ($this->_aObserver as $observer)
{
try {
if (method_exists($observer, 'vOnUpdate')) {
$observer->vOnUpdate();
}
} catch(\Exception $e) {
// echo 'Caught exception: '.$e->getMessage();
}
}
I am trying to use a try/catch block to add in some error handling for a custom WordPress plugin that gets Tweets via the Twitter API.
For testing purposes, I am throwing an exception in my class construct method.
class Twitter_Settings() {
public function __construct() {
throw new \Exception('test');
}
}
then in my plugin file, I am doing:
function twitter_init_settings() {
try {
return new Twitter_Settings();
} catch ( Exception $e ) {
echo $e->getMessage();
}
}
twitter_init_settings();
On the frontend, where I am spitting out $tweets = twitter_feed()->output_feed(); (with a foreach loop afterwards) I am getting an Uncaught Exception error. Oddly, it shows the custom message, 'test', so it must know about my exception, so why is it saying it is uncaught?
Uncaught Exception error happen while an exception is not catched (in try catch statements)
Remove the return statment because the catch might not be reached.
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.
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
basically i have a custom exception handler. When i handle an exception, i just want it to echo the message and continue the script. But after my method handles the exception, the script doesnt continue.
Is this a behaviour of php or is my exception handler doing something wrong?
This is a behavior of php. This differs from set_error_handler() in that, according to the manual on set_exception_handler(), Execution will stop after the exception_handler is called. Therefore, ensure you catch all exceptions, letting only those you want to kill your script through.
This is actually why set_error_handler() doesn't pair well with exceptions and set_exception_handler() when converting all errors to exceptions... unless you actually mean your application to be so strictly coded that any notice or warning halts the script. But at least it gives you a trace on that call involving an unset array key.
With a custom exception handler, you'll want to catch the exception in a try/catch block and do whatever handling you want in there.
The following is the example from The CodeUnit of Craig
try {
$error = 'Throw this error';
throw new Exception($error);
echo 'Never get here';
}
catch (Exception $e)
{
echo 'Exception caught: ', $e->getMessage(), "\n";
}
If you want to catch and print any unhandled exception, you can set a top level exception handler like this example from w3schools(near the bottom of the page)
<?php
function myException($exception){
echo "<b>Exception:</b> " , $exception->getMessage();
}
set_exception_handler('myException');
throw new Exception('Uncaught Exception occurred');
?>
should print: "Exception: Uncaught Exception occurred"
Look at the following code. it worked for me:
define(BR, "<br/>");
try {
echo "throwing exception" . BR;
throw new Exception("This is exception");
}
catch(Exception $ex) {
echo "caught exception: " . BR . $ex->getMessage() . BR;
}
echo "Keep on going!. ..." . BR;
it prints the following:
throwing exception
caught exception:
This is exception
Keep on going!. ...
What do you say ?
Can you show the code of your code handler ?
You could do this :
function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
if (error_reporting() & $errno) {
// only process when included in error_reporting
return processError($errno, $errstring);
}
return true;
}
function handleException($exception){
// Here, you do whatever you want with the generated
// exceptions. You can store them in a file or database,
// output them in a debug section of your page or do
// pretty much anything else with it, as if it's a
// normal variable
}
function processError($code, $message){
switch ($code) {
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
// Throw exception and stop execution of script
throw new Exception($message, $code);
default:
// Execute exception handler and continue execution afterwards
return handleException(new Exception($message, $code));
}
}
// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');
// ---------------------------------- //
// Generate warning
processError(E_USER_WARNING, 'This went wrong, but we can continue');
// Generate fatal error :
processError(E_USER_ERROR, 'This went horrible wrong');
Alternate approach :
function handleError($errno, $errstring, $errfile, $errline, $errcontext) {
if (error_reporting() & $errno) {
// only process when included in error_reporting
return handleException(new \Exception($errstring, $errno));
}
return true;
}
function handleException($exception){
// Here, you do whatever you want with the generated
// exceptions. You can store them in a file or database,
// output them in a debug section of your page or do
// pretty much anything else with it, as if it's a
// normal variable
switch ($code) {
case E_ERROR:
case E_CORE_ERROR:
case E_USER_ERROR:
// Make sure script exits here
exit(1);
default:
// Let script continue
return true;
}
}
// Set error handler to your custom handler
set_error_handler('handleError');
// Set exception handler to your custom handler
set_exception_handler('handleException');
// ---------------------------------- //
// Generate warning
trigger_error('This went wrong, but we can continue', E_USER_WARNING);
// Generate fatal error :
trigger_error('This went horrible wrong', E_USER_ERROR);
An advantage of the latter strategy, is that you get the $errcontext parameter if you do $exception->getTrace() within the function handleException.
This is very useful for certain debugging purposes. Unfortunately, this works only if you use trigger_error directly from your context, which means you can't use a wrapper function/method to alias the trigger_error function (so you can't do something like function debug($code, $message) { return trigger_error($message, $code); } if you want the context data in your trace).
EDIT
I've found one dirty workaround for the trigger_error problem.
Consider the following code :
define("__DEBUG__", "Use of undefined constant DEBUG - assumed 'DEBUG'");
public static function handleError($code, $message, $file, $line, $context = false) {
if ($message == __DEBUG__) {
return static::exception(new \Exception(__DEBUG__, E_USER_WARNING));
} else {
if (error_reporting() & $code) {
return static::exception(new \Exception($message, $code));
}
return true;
}
}
public static function handleException($e) {
global $debug;
$code = $e->getCode();
$trace = $e->getTrace();
if ($e->getMessage() == __DEBUG__) {
// DEBUG
array_push($debug, array(
'__TIME__' => microtime(),
'__CONTEXT__' => array(
'file' => $trace[0]['file'],
'line' => $trace[0]['line'],
'function' => $trace[1]['function'],
'class' => $trace[1]['class'],
'type' => $trace[1]['type'],
'args' => $trace[0]['args'][4]
)
));
} else {
// NORMAL ERROR HANDLING
}
return true;
}
With this code, you can use the statement DEBUG; to generate a list of all available variables and a stack trace for any specific context. This list is stored in the global variable $debug. You can add it to a log file, add it to a database or print it out.
This is a VERY, VERY dirty hack, though, so use it at your own discretion. However, it can make debugging a lot easier and allows you to create a clean UI for your debug code.