I throw an exception inside à file.php I want to catch and display the trace for debugging, but the trace is incomplete when I get it with $exception->getTraceAsString(). The trace is correct when I use debug_print_backtrace() inside the exception constructor:
# page.php, called by index.php
<?php
class CustomException extends Exception {
public function __construct($message = "", $code = 0, $previous = null) {
echo '<pre>';
debug_print_backtrace();
echo '</pre>';
parent::__construct($message, $code, $previous);
}
}
try {
include('file.php'); // throw a CustomException
} catch (CustomException $e) {
echo '<pre>' . $e->getTraceAsString() . '</pre>';
echo '<hr>';
echo '</pre>';
}
# output of debug_print_backtrace():
#0 App\Exception… called at [/path/to/file.php:1396]
#1 include(/path/to/file.php) called at [/path/to/page.php:3]
#2 require_once(/path/to/page.php) called at [/path/to/index.php:100]
# output of $e->getTraceAsString():
#0 /path/to/page.php(3): include()
#1 /path/to/index.php(100): require_once('/path/to/i...')
#2 {main}
Is there a way to get the full traceAsString (and more important for me, the output of $e->getTrace()) ?
getTrace()/getTraceAsString() seems to be just the trace, but not the error message. You can always build your own line, which can also help with readability. I use something like this on a lot of my logging, which is useful even when I don't include the trace:
$error_string = "Error with (whatever it is), ".$e->getMessage() . " on " . $e->getLine() . " of " . $e->getFile();
You can also check to see what kind of exception it might be:
$error_string .= " - Exception of type ".get_class($e);
Related
I have this kind of loop. On each iteration it should include a file, Included files can come with errors. Once some of included files gets an error the whole process of getting lost. How to prevent breaking of the process?
I tried this try catch but it errors from included files still cause stopping execution of file.
Thanks
foreach ($li_arrays as $index => $li_array) {
if($index == 0){
try {
require 'update.php';
} catch(Exception $e) {
echo "Exception caught with message: " . $e->getMessage() . "\n";
}
}
elseif ($index == 1){
try {
require 'update1.php';
} catch(Exception $e) {
echo "Exception caught with message: " . $e->getMessage() . "\n";
}
}else{
try {
require 'update2.php';
} catch(Exception $e) {
echo "Exception caught with message: " . $e->getMessage() . "\n";
}
}
Errors in php are not recoverable, so they will always lead to the termination of your script.
I am not even sure that you are even talking about Errors, though if you are, this is the answer to your question.
Another thing to be aware of:
Require will throw an E_COMPILE_ERROR if the required file doesn't exist, which is also something you won't be able to catch.
If you don't want to terminate if the script isn't found, use include instead.
At the end I changed "require" with "include" and used this try-catch approach inside each included file.
$attempts = 0;
do {
try
{
////PHP code ///
} catch (Exception $e) {
echo "\n\n======EXCEPTION======\n\n";
var_dump($e);
$attempts++;
sleep(30);
continue;
}
break;
} while($attempts < 5);
I have code that causes 2 errors, 1 from the php function pg_query_params because I've input an invalid query, and the Exception that I throw when the result of that function is false:
if (!$res = pg_query_params($this->sql, $this->args)) {
// note pg_last_error seems to often not return anything
$msg = pg_last_error() . " " . $this->sql . PHP_EOL . " Args: " . var_export($this->args, true);
throw new \Exception("Query Execution Failure: $msg");
}
Then I have error handler code which logs the errors and is supposed to echo them. Both errors are logged, but only the last (the thrown exception) is echoed. I'd like both echoed, as the first contains helpful debugging info. I don't understand why both aren't, as I've done some debugging and echo is called for both errors. Is it something related to output buffering or a concurrency issue?
Here is a shortened version of my error handler code. The throwableHandler method is registered with set_exception_handler() and the phpErrorHandler method with set_error_handler(). I haven't included generateMessageBodyCommon() but it simply adds error info to the message body:
private function handleError(string $messageBody, int $errno)
{
// echo
if ($this->echoErrors) {
$messageBody .= 'inside echo'; // this goes into the log file for both errors
echo nl2br($messageBody, false);
}
// log
#error_log($messageBody, 3, $this->logPath);
}
public function throwableHandler(\Throwable $e)
{
$message = $this->generateMessageBodyCommon($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
$message .= PHP_EOL . "Stack Trace:" . PHP_EOL . $e->getTraceAsString();
$this->handleError($message, $e->getCode(), $exitPage);
}
public function phpErrorHandler(int $errno, string $errstr, string $errfile = null, string $errline = null)
{
$message = $this->generateMessageBodyCommon($errno, $errstr, $errfile, $errline) . PHP_EOL . "Stack Trace:". PHP_EOL . $this->getDebugBacktraceString();
$this->handleError($message, $errno, false);
}
Be careful with '#' -> #error_log($messageBody, 3, $this->logPath);
PHP supports one error control operator: the at sign (#). When prepended to an expression in PHP, any error messages that might be generated by that expression will be ignored.
http://php.net/manual/en/language.operators.errorcontrol.php
Error level :
error_reporting(E_ALL);
http://www.php.net/manual/en/function.error-reporting.php
error_reporting — Sets which PHP errors are reported
If i have a c1.php
<?php
class C1 {
function f1($value) {
if($value == 'ok') {
echo "OK!";
} else {
throw new Exception("WRONG!");
}
}
}
?>
and index.php
<?php
require_once('c1.php');
$c = new C1();
$c->f1('ok');
$c->f1('asd');
?>
Can anybody know, how to construct a well readable error message like "Error: you have wrong value in C:\xampp\htdocs\projekt\index.php: line 5" instead of tracktracing
OK!
Fatal error: Uncaught exception 'Exception' with message 'WRONG!' in
C:\xampp\htdocs\projekt\c1.php:7 Stack trace: #0
C:\xampp\htdocs\projekt\index.php(5): C1->f1('asd') #1 {main} thrown in
C:\xampp\htdocs\projekt\c1.php on line 7
that reading is a little difficult.
Catch the exception. This is the point of exceptions.. they are catchable and you can do something with the information (for instance.. output just the message).
You can do something like this:
try {
$c = new C1();
$c->f1('ok');
$c->f1('asd');
} catch(Exception $e) {
echo 'Error: you have wrong value in ', $e->getFile(), ' on line ', $e->getLine();
// ... code
}
i caught it
try {
..
} catch(Exception $e) {
//echo $e->getTraceAsString();
$t = $e->getTrace();
$t = $t[0];
echo 'Error: file - ',$t['file'],' - line: ',$t['line'],
' - function: ',$t['function'],'; ',$e->getMessage();
}
thank you for hints.
Simple, don't use an exception. They should be used when you're doing a try-catch or for an exceptional situation. This is not exceptional - meaning nothing can possibly turn an error with just a if-else statement.
So just echo out the error message of your choice.
I've written the following custom Exception handler:
namespace System\Exception;
class Handler extends \Exception {
public static function getException($e = null) {
if (ENVIRONMENT === 0 && is_object($e)) {
$message = "<p>";
$message .= "Exception: " . $e->getMessage();
$message .= "<br />File: " . $e->getFile();
$message .= "<br />Line: " . $e->getLine();
$message .= "<br />Trace: " . $e->getTrace();
$message .= "<br />Trace as string: " . $e->getTraceAsString();
$message .= "</p>";
} else {
$message = '<h1>Exception</h1>';
$message .= '<p>There was a problem.</p>';
}
#require_once('header.php');
echo $message;
#require_once('footer.php');
exit();
}
public static function getError($errno = 0, $errstr = null, $errfile = null, $errline = 0) {
if (ENVIRONMENT === 0) {
$message = "<p>";
$message .= "Error: " . $errstr;
$message .= "<br />File: " . $errfile;
$message .= "<br />Line: " . $errline;
$message .= "<br />Number: " . $errno;
$message .= "</p>";
} else {
$message = '<h1>Error</h1>';
$message .= '<p>There was a problem.</p>';
}
#require_once('header.php');
echo $message;
#require_once('footer.php');
exit();
}
public static function getShutdown() {
$last_error = error_get_last();
if ($last_error['type'] === E_ERROR) {
self::getError(E_ERROR, $last_error['message'], $last_error['file'], $last_error['line']);
}
}
}
and have indicated that I want to use this class and its methods for processing all exceptions and errors generated by the system in the following way:
set_exception_handler(array("System\Exception\Handler", "getException"));
set_error_handler(array("System\Exception\Handler", "getError"), -1 & ~E_NOTICE & ~E_USER_NOTICE);
register_shutdown_function(array("System\Exception\Handler", "getShutdown"));
I have also indicated that I don't want errors to be displayed on the screen and wand to report all of the errors:
ini_set('display_errors', 'Off');
error_reporting(-1);
My question now is - do I still need to use the try { } catch () { } statement in order to catch any exceptions and errors? I know that the above is most probably not a bullet proof, but seem to be working so far without any try / catch statement by processing all uncaught exceptions and errors.
Also - is there any disadvantage by using custom exception handler and letting it catch all uncaught exceptions rather than doing this via try {} catch (i.e. performance / security etc.)?
You don't have to, but you cannot recover - using try/catch gives you the advantage of reacting to particular exception (for example file not found in some_custom_session_handling() might be a good place to use try/catch and log out such user without session file).
So the advantage is that you have prettier messages. The downside is that you treat exceptions always the same. It's not bad in itself, and should not degradate performance or security, but it misses the point of using exceptions in the first place.
However, it does not exclude using try/catch where you might want them, so I'd say it's a good failover solution, but should be avoided as a try/catch replacement
As jderda said, be using your aproach you are missing the point of exceptions: to check for any errors in the upper levels of your code and react to them - halt or treat the exception and move on. Your aproach is fine when you want to, for example, log all uncaught exceptions
I can't do something like this ?
try {
require_once( '/includes/functions.php' );
}
catch(Exception $e) {
echo "Message : " . $e->getMessage();
echo "Code : " . $e->getCode();
}
No error is echoed, server returns 500.
You can do it with include_once or file_exists:
try {
if (! #include_once( '/includes/functions.php' )) // # - to suppress warnings,
// you can also use error_reporting function for the same purpose which may be a better option
throw new Exception ('functions.php does not exist');
// or
if (!file_exists('/includes/functions.php' ))
throw new Exception ('functions.php does not exist');
else
require_once('/includes/functions.php' );
}
catch(Exception $e) {
echo "Message : " . $e->getMessage();
echo "Code : " . $e->getCode();
}
As you can read here : (emph mine)
require() is identical to include()
except upon failure it will also
produce a fatal E_COMPILE_ERROR level
error. In other words, it will halt
the script
This is about require, but that is equivalent to require_once(). This is not a catchable error.
By the way, you need to enter the absolute path, and I don't think this is right:
require_once( '/includes/functions.php' );
You might want something like this
require_once( './includes/functions.php' );
Or, if you're calling this from a subdir or from a file that is included in different dirs, you might need something like
require_once( '/var/www/yourPath/includes/functions.php' );
This should work, but it is a bit of a hack.
if(!#include_once("path/to/script.php")) {
//Logic here
}