PHP: exceptions vs errors? - php

Maybe I'm missing it somewhere in the PHP manual, but what exactly is the difference between an error and an exception? The only difference that I can see is that errors and exceptions are handled differently. But what causes an exception and what causes an error?

Exceptions are thrown - they are intended to be caught. Errors are generally unrecoverable. Lets say for instance - you have a block of code that will insert a row into a database. It is possible that this call fails (duplicate ID) - you will want to have a "Error" which in this case is an "Exception". When you are inserting these rows, you can do something like this
try {
$row->insert();
$inserted = true;
} catch (Exception $e) {
echo "There was an error inserting the row - ".$e->getMessage();
$inserted = false;
}
echo "Some more stuff";
Program execution will continue - because you 'caught' the exception. An exception will be treated as an error unless it is caught. It will allow you to continue program execution after it fails as well.

I usually set_error_handler to a function that takes the error and throws an exception so that whatever happens i'll just have exceptions to deal with. No more #file_get_contents just nice and neat try/catch.
In debug situations i also have an exception handler that outputs an asp.net like page. I'm posting this on the road but if requested I will post example source later.
edit:
Addition as promised, I've cut and pasted some of my code together to make a sample.
<?php
define( 'DEBUG', true );
class ErrorOrWarningException extends Exception
{
protected $_Context = null;
public function getContext()
{
return $this->_Context;
}
public function setContext( $value )
{
$this->_Context = $value;
}
public function __construct( $code, $message, $file, $line, $context )
{
parent::__construct( $message, $code );
$this->file = $file;
$this->line = $line;
$this->setContext( $context );
}
}
/**
* Inspire to write perfect code. everything is an exception, even minor warnings.
**/
function error_to_exception( $code, $message, $file, $line, $context )
{
throw new ErrorOrWarningException( $code, $message, $file, $line, $context );
}
set_error_handler( 'error_to_exception' );
function global_exception_handler( $ex )
{
ob_start();
dump_exception( $ex );
$dump = ob_get_clean();
// send email of dump to administrator?...
// if we are in debug mode we are allowed to dump exceptions to the browser.
if ( defined( 'DEBUG' ) && DEBUG == true )
{
echo $dump;
}
else // if we are in production we give our visitor a nice message without all the details.
{
echo file_get_contents( 'static/errors/fatalexception.html' );
}
exit;
}
function dump_exception( Exception $ex )
{
$file = $ex->getFile();
$line = $ex->getLine();
if ( file_exists( $file ) )
{
$lines = file( $file );
}
?><html>
<head>
<title><?= $ex->getMessage(); ?></title>
<style type="text/css">
body {
width : 800px;
margin : auto;
}
ul.code {
border : inset 1px;
}
ul.code li {
white-space: pre ;
list-style-type : none;
font-family : monospace;
}
ul.code li.line {
color : red;
}
table.trace {
width : 100%;
border-collapse : collapse;
border : solid 1px black;
}
table.thead tr {
background : rgb(240,240,240);
}
table.trace tr.odd {
background : white;
}
table.trace tr.even {
background : rgb(250,250,250);
}
table.trace td {
padding : 2px 4px 2px 4px;
}
</style>
</head>
<body>
<h1>Uncaught <?= get_class( $ex ); ?></h1>
<h2><?= $ex->getMessage(); ?></h2>
<p>
An uncaught <?= get_class( $ex ); ?> was thrown on line <?= $line; ?> of file <?= basename( $file ); ?> that prevented further execution of this request.
</p>
<h2>Where it happened:</h2>
<? if ( isset($lines) ) : ?>
<code><?= $file; ?></code>
<ul class="code">
<? for( $i = $line - 3; $i < $line + 3; $i ++ ) : ?>
<? if ( $i > 0 && $i < count( $lines ) ) : ?>
<? if ( $i == $line-1 ) : ?>
<li class="line"><?= str_replace( "\n", "", $lines[$i] ); ?></li>
<? else : ?>
<li><?= str_replace( "\n", "", $lines[$i] ); ?></li>
<? endif; ?>
<? endif; ?>
<? endfor; ?>
</ul>
<? endif; ?>
<? if ( is_array( $ex->getTrace() ) ) : ?>
<h2>Stack trace:</h2>
<table class="trace">
<thead>
<tr>
<td>File</td>
<td>Line</td>
<td>Class</td>
<td>Function</td>
<td>Arguments</td>
</tr>
</thead>
<tbody>
<? foreach ( $ex->getTrace() as $i => $trace ) : ?>
<tr class="<?= $i % 2 == 0 ? 'even' : 'odd'; ?>">
<td><?= isset($trace[ 'file' ]) ? basename($trace[ 'file' ]) : ''; ?></td>
<td><?= isset($trace[ 'line' ]) ? $trace[ 'line' ] : ''; ?></td>
<td><?= isset($trace[ 'class' ]) ? $trace[ 'class' ] : ''; ?></td>
<td><?= isset($trace[ 'function' ]) ? $trace[ 'function' ] : ''; ?></td>
<td>
<? if( isset($trace[ 'args' ]) ) : ?>
<? foreach ( $trace[ 'args' ] as $i => $arg ) : ?>
<span title="<?= var_export( $arg, true ); ?>"><?= gettype( $arg ); ?></span>
<?= $i < count( $trace['args'] ) -1 ? ',' : ''; ?>
<? endforeach; ?>
<? else : ?>
NULL
<? endif; ?>
</td>
</tr>
<? endforeach;?>
</tbody>
</table>
<? else : ?>
<pre><?= $ex->getTraceAsString(); ?></pre>
<? endif; ?>
</body>
</html><? // back in php
}
set_exception_handler( 'global_exception_handler' );
class X
{
function __construct()
{
trigger_error( 'Whoops!', E_USER_NOTICE );
}
}
$x = new X();
throw new Exception( 'Execution will never get here' );
?>

The answer deserves talking about the elephant in the room
Errors is the old way of handling an error condition at run-time. Typically the code would make a call to something like set_error_handler before executing some code. Following the tradition of assembly language interrupts. Here is how some BASIC code would look.
on error :divide_error
print 1/0
print "this won't print"
:divide_error
if errcode = X
print "divide by zero error"
It was hard to make sure that set_error_handler would be called with the right value. And even worse, a call could be made to a separate procedure that would change the error handler. Plus many times calls were interspersed with set_error_handler calls and handlers. It was easy for code to quickly get out of control. Exception handling came to the rescue by formalizing syntax and semantics of what good code was really doing.
try {
print 1/0;
print "this won't print";
} catch (DivideByZeroException $e) {
print "divide by zero error";
}
No separate function or risk of calling the wrong error handler. The code now is guaranteed to be in the same place. Plus we get better error messages.
PHP used to only have error handling, when many other languages already had evolved to the preferable exception handling model. Eventually the makers of PHP implemented exception handling. But likely to support old code, they kept error handling and provided a way to make error handling look like exception handling. Except that, there is no guarantee that some code may not reset the error handler which was precisely what exception handling was meant to provide.
Final answer
Errors that were coded before exception handling was implemented, are likely still errors. New errors are likely exceptions. But there is no design or logic to which are errors and which are exceptions. It's just based in what was available at the time it was coded, and the preference of the programmer coding it.

One thing to add here is about handling exceptions and errors. For the purpose of the application developer, both errors and exceptions are "bad things" that you want to record to learn about the problems that your application has - so that your customers have a better experience in the long run.
So it makes sense to write an error handler that does the same thing as what you do for exceptions.

As stated in other answers, setting error handler to exception thrower is the best way to handle errors in PHP. I use a bit simpler setup:
set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
if (error_reporting()) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
});
Please note the error_reporting() check to keep # operator working. Also, there is no need to define custom exception, PHP has one nice class for that.
Great benefit of throwing exceptions is that exception has stack trace associated with them, so it is easy to find where is the problem.

Re: "but what exactly is the difference between an error and an exception?"
There are a lot of good answers about the differences here. I'll just add in something that hasn't yet been talked about - performance. Specifically, this is for the difference between throwing/handling exceptions and handling a return code (either success or some error). Usually, in php, this means returning false or null, but they can be more detailed such as with file uploading: http://php.net/manual/en/features.file-upload.errors.php You could even return an Exception object!
I've done a few performance runs in different languages/systems. Generally speaking, exception handling is about 10,000x slower than checking for an error return code.
So, if it absolutely, positively needs to finish executing before it even started - well, you're out of luck because time travel doesn't exist. Without time travel, return codes are the fastest option available.
Edit:
PHP is highly optimized for exception handling. Real world tests show that throwing an exception is only 2-10x slower than returning a value.

I think the anwser you're looking for is that;
Errors are the standard stuff you're used to, like echoing a $variable that doesnt exist.
Exceptions are only from PHP 5 onwards and come when dealing with objects.
To keep it simple:
Exceptions are the errors you get when dealing with objects.
The try/catch statement lets you do something about them though, and is used much like the if/else statement.
Try to do this, if problem, doesnt matter, do this.
If you dont "catch" an exception, then it turns into a standard error.
Errors are the php fundemental errors which usually halt your script.
Try/catch is often used for establishing database connections like PDO, which is fine if you want to redirect the script or do something else if the connection doesnt work. But if you just want to display the error message and stop the script then you dont need it, the uncaught exception turns into a fatal error. Or you can use a site-wide error handling setting as well.
Hope that helps

From PHP: Exceptions - Manual:
As of PHP 7.1.0, a catch block may specify multiple exceptions using the pipe (|) character. This is useful for when different exceptions from different class hierarchies are handled the same.
try {
// do something
} catch (Error | Exception $e) {
echo $e->getMessage();
}

Exceptions are thrown intentionally by code using a throw, errors... not so much.
Errors come about as a result of something which isn't handled typically. (IO errors, TCP/IP errors, null reference errors)

I intend to give you a most unusual discussion of error control.
I built a very good error handler into a language years ago, and though some of the names have changed, the principles of error processing are the same today. I had a custom built multi-tasking OS and had to be able to recover from data errors at all levels with no memory leaks, stack growth or crashes. So what follows is my understanding of how errors and exceptions must operate and how they differ. I will just say I do not have an understanding of how the internals of try catch works, so am guessing to some measure.
The first thing that happens under the covers for error processing is jumping from one program state to another. How is that done? I'll get to that.
Historically, errors are older and simpler, and exceptions are newer and a bit more complex and capable. Errors work fine until you need to bubble them up, which is the equivalent of handing a difficult problem to your supervisor.
Errors can be numbers, like error numbers, and sometimes with one or more associated strings. For example if a file-read error occurs you might be able to report what it is and possibly gracefully fail. (Hay, it's a step up from just crashing like in the old days.)
What is not often said about exceptions is that exceptions are objects layered on a special exception stack. It's like a return stack for program flow, but it holds a return state just for error trys and catches. (I used to call them ePush and ePop, and ?Abort was a conditional throw which would ePop and recover to that level, while Abort was a full die or exit.)
On the bottom of the stack is the information about the initial caller, the object that knows about the state when the outer try was started, which is often when your program was started. On top that, or the next layer on the stack, with up being the children, and down being the parents, is the exception object of the next inner try/catch block.
If you put a try inside a try you are stacking the inner try on top of the outer try. When an error occurs in the inner try and either the inner catch can't handle it or the error is thrown to the outer try, then control is passed to the outer catch block (object) to see if it can handle the error, i.e. your supervisor.
So what this error stack really does is to be able to mark and restore program flow and system state, in other words, it allows a program to not crash the return stack and mess up things for others (data) when things go wrong. So it also saves the state of any other resources like memory allocation pools and so it can clean them up when catch is done. In general this can be a very complicated thing, and that is why exception handling is often slow. In general quite a bit of state needs to go into these exception blocks.
So a try/catch block sort of sets a state to be able to return to if all else gets messed up. It's like a parent. When our lives get messed up we can fall back into our parent's lap and they will make it all right again.
Hope I didn't disappoint you.

Once set_error_handler() is defined, error handler is similar to Exception's. See code below:
<?php
function handleErrors( $e_code ) {
echo "error code: " . $e_code . "<br>";
}
set_error_handler( "handleErrors" );
trigger_error( "trigger a fatal error", E_USER_ERROR);
echo "after error."; //it would run if set_error_handler is defined, otherwise, it wouldn't show
?>

You may add this comment
function doSomething()
{
/** #noinspection PhpUnhandledExceptionInspection */
throw new Exception();
}

Related

Prevent PHP from echoing if exception occured

I noticed that PHP's echo successfully prints strings even if somewhere in the script an error is thrown and not handled. For example:
error_reporting(E_ALL);
ini_set('display_errors', 1);
echo "started";
throw new Exception("big error");
echo "done";
prints "started", even though an error occured. The status code is 500 indeed, but I don't think displaying partial results works for all cases.
Using ob_start() and ob_get_contents() offers some flexibility, but I expected that PHP offers a switch to set displaying to none if error occured. Does this switch exist?
when you say throw new Exception() this means you are saying move the program control to caller and don't execute the further statements after this throw statement.
thanks to: Difference between "throw new Exception" and "new Exception"?
echo "started"; // <- This will occurs
throw new Exception("big error"); // <- And here the Exception will be thrown
echo "done"; // <- therefore, this line won't be reached
One way to solve this would be using a variable to store what you want to echo and only echo it if there are no uncaught exceptions
$echoStr = "";
$echoStr .="started";
throw new Exception("big error");
$echoStr .="done";
echo $echoStr;
Echo instantly send the data to the server (at least in this code it does) and no longer can be affected by what happens next. It's generally bad practice to work like that (eg: after an echo you can no longer change headers like a redirect, which can be very inconfinient), better would be to stored everything in a variable and output it when you want:
$output = "started";
throw new Exception("big error");
$output.= "done";
echo $output; // or if in a function, return instead of echo

php try catch with database query not catcing error [duplicate]

Maybe I'm missing it somewhere in the PHP manual, but what exactly is the difference between an error and an exception? The only difference that I can see is that errors and exceptions are handled differently. But what causes an exception and what causes an error?
Exceptions are thrown - they are intended to be caught. Errors are generally unrecoverable. Lets say for instance - you have a block of code that will insert a row into a database. It is possible that this call fails (duplicate ID) - you will want to have a "Error" which in this case is an "Exception". When you are inserting these rows, you can do something like this
try {
$row->insert();
$inserted = true;
} catch (Exception $e) {
echo "There was an error inserting the row - ".$e->getMessage();
$inserted = false;
}
echo "Some more stuff";
Program execution will continue - because you 'caught' the exception. An exception will be treated as an error unless it is caught. It will allow you to continue program execution after it fails as well.
I usually set_error_handler to a function that takes the error and throws an exception so that whatever happens i'll just have exceptions to deal with. No more #file_get_contents just nice and neat try/catch.
In debug situations i also have an exception handler that outputs an asp.net like page. I'm posting this on the road but if requested I will post example source later.
edit:
Addition as promised, I've cut and pasted some of my code together to make a sample.
<?php
define( 'DEBUG', true );
class ErrorOrWarningException extends Exception
{
protected $_Context = null;
public function getContext()
{
return $this->_Context;
}
public function setContext( $value )
{
$this->_Context = $value;
}
public function __construct( $code, $message, $file, $line, $context )
{
parent::__construct( $message, $code );
$this->file = $file;
$this->line = $line;
$this->setContext( $context );
}
}
/**
* Inspire to write perfect code. everything is an exception, even minor warnings.
**/
function error_to_exception( $code, $message, $file, $line, $context )
{
throw new ErrorOrWarningException( $code, $message, $file, $line, $context );
}
set_error_handler( 'error_to_exception' );
function global_exception_handler( $ex )
{
ob_start();
dump_exception( $ex );
$dump = ob_get_clean();
// send email of dump to administrator?...
// if we are in debug mode we are allowed to dump exceptions to the browser.
if ( defined( 'DEBUG' ) && DEBUG == true )
{
echo $dump;
}
else // if we are in production we give our visitor a nice message without all the details.
{
echo file_get_contents( 'static/errors/fatalexception.html' );
}
exit;
}
function dump_exception( Exception $ex )
{
$file = $ex->getFile();
$line = $ex->getLine();
if ( file_exists( $file ) )
{
$lines = file( $file );
}
?><html>
<head>
<title><?= $ex->getMessage(); ?></title>
<style type="text/css">
body {
width : 800px;
margin : auto;
}
ul.code {
border : inset 1px;
}
ul.code li {
white-space: pre ;
list-style-type : none;
font-family : monospace;
}
ul.code li.line {
color : red;
}
table.trace {
width : 100%;
border-collapse : collapse;
border : solid 1px black;
}
table.thead tr {
background : rgb(240,240,240);
}
table.trace tr.odd {
background : white;
}
table.trace tr.even {
background : rgb(250,250,250);
}
table.trace td {
padding : 2px 4px 2px 4px;
}
</style>
</head>
<body>
<h1>Uncaught <?= get_class( $ex ); ?></h1>
<h2><?= $ex->getMessage(); ?></h2>
<p>
An uncaught <?= get_class( $ex ); ?> was thrown on line <?= $line; ?> of file <?= basename( $file ); ?> that prevented further execution of this request.
</p>
<h2>Where it happened:</h2>
<? if ( isset($lines) ) : ?>
<code><?= $file; ?></code>
<ul class="code">
<? for( $i = $line - 3; $i < $line + 3; $i ++ ) : ?>
<? if ( $i > 0 && $i < count( $lines ) ) : ?>
<? if ( $i == $line-1 ) : ?>
<li class="line"><?= str_replace( "\n", "", $lines[$i] ); ?></li>
<? else : ?>
<li><?= str_replace( "\n", "", $lines[$i] ); ?></li>
<? endif; ?>
<? endif; ?>
<? endfor; ?>
</ul>
<? endif; ?>
<? if ( is_array( $ex->getTrace() ) ) : ?>
<h2>Stack trace:</h2>
<table class="trace">
<thead>
<tr>
<td>File</td>
<td>Line</td>
<td>Class</td>
<td>Function</td>
<td>Arguments</td>
</tr>
</thead>
<tbody>
<? foreach ( $ex->getTrace() as $i => $trace ) : ?>
<tr class="<?= $i % 2 == 0 ? 'even' : 'odd'; ?>">
<td><?= isset($trace[ 'file' ]) ? basename($trace[ 'file' ]) : ''; ?></td>
<td><?= isset($trace[ 'line' ]) ? $trace[ 'line' ] : ''; ?></td>
<td><?= isset($trace[ 'class' ]) ? $trace[ 'class' ] : ''; ?></td>
<td><?= isset($trace[ 'function' ]) ? $trace[ 'function' ] : ''; ?></td>
<td>
<? if( isset($trace[ 'args' ]) ) : ?>
<? foreach ( $trace[ 'args' ] as $i => $arg ) : ?>
<span title="<?= var_export( $arg, true ); ?>"><?= gettype( $arg ); ?></span>
<?= $i < count( $trace['args'] ) -1 ? ',' : ''; ?>
<? endforeach; ?>
<? else : ?>
NULL
<? endif; ?>
</td>
</tr>
<? endforeach;?>
</tbody>
</table>
<? else : ?>
<pre><?= $ex->getTraceAsString(); ?></pre>
<? endif; ?>
</body>
</html><? // back in php
}
set_exception_handler( 'global_exception_handler' );
class X
{
function __construct()
{
trigger_error( 'Whoops!', E_USER_NOTICE );
}
}
$x = new X();
throw new Exception( 'Execution will never get here' );
?>
The answer deserves talking about the elephant in the room
Errors is the old way of handling an error condition at run-time. Typically the code would make a call to something like set_error_handler before executing some code. Following the tradition of assembly language interrupts. Here is how some BASIC code would look.
on error :divide_error
print 1/0
print "this won't print"
:divide_error
if errcode = X
print "divide by zero error"
It was hard to make sure that set_error_handler would be called with the right value. And even worse, a call could be made to a separate procedure that would change the error handler. Plus many times calls were interspersed with set_error_handler calls and handlers. It was easy for code to quickly get out of control. Exception handling came to the rescue by formalizing syntax and semantics of what good code was really doing.
try {
print 1/0;
print "this won't print";
} catch (DivideByZeroException $e) {
print "divide by zero error";
}
No separate function or risk of calling the wrong error handler. The code now is guaranteed to be in the same place. Plus we get better error messages.
PHP used to only have error handling, when many other languages already had evolved to the preferable exception handling model. Eventually the makers of PHP implemented exception handling. But likely to support old code, they kept error handling and provided a way to make error handling look like exception handling. Except that, there is no guarantee that some code may not reset the error handler which was precisely what exception handling was meant to provide.
Final answer
Errors that were coded before exception handling was implemented, are likely still errors. New errors are likely exceptions. But there is no design or logic to which are errors and which are exceptions. It's just based in what was available at the time it was coded, and the preference of the programmer coding it.
One thing to add here is about handling exceptions and errors. For the purpose of the application developer, both errors and exceptions are "bad things" that you want to record to learn about the problems that your application has - so that your customers have a better experience in the long run.
So it makes sense to write an error handler that does the same thing as what you do for exceptions.
As stated in other answers, setting error handler to exception thrower is the best way to handle errors in PHP. I use a bit simpler setup:
set_error_handler(function ($errno, $errstr, $errfile, $errline ) {
if (error_reporting()) {
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}
});
Please note the error_reporting() check to keep # operator working. Also, there is no need to define custom exception, PHP has one nice class for that.
Great benefit of throwing exceptions is that exception has stack trace associated with them, so it is easy to find where is the problem.
Re: "but what exactly is the difference between an error and an exception?"
There are a lot of good answers about the differences here. I'll just add in something that hasn't yet been talked about - performance. Specifically, this is for the difference between throwing/handling exceptions and handling a return code (either success or some error). Usually, in php, this means returning false or null, but they can be more detailed such as with file uploading: http://php.net/manual/en/features.file-upload.errors.php You could even return an Exception object!
I've done a few performance runs in different languages/systems. Generally speaking, exception handling is about 10,000x slower than checking for an error return code.
So, if it absolutely, positively needs to finish executing before it even started - well, you're out of luck because time travel doesn't exist. Without time travel, return codes are the fastest option available.
Edit:
PHP is highly optimized for exception handling. Real world tests show that throwing an exception is only 2-10x slower than returning a value.
I think the anwser you're looking for is that;
Errors are the standard stuff you're used to, like echoing a $variable that doesnt exist.
Exceptions are only from PHP 5 onwards and come when dealing with objects.
To keep it simple:
Exceptions are the errors you get when dealing with objects.
The try/catch statement lets you do something about them though, and is used much like the if/else statement.
Try to do this, if problem, doesnt matter, do this.
If you dont "catch" an exception, then it turns into a standard error.
Errors are the php fundemental errors which usually halt your script.
Try/catch is often used for establishing database connections like PDO, which is fine if you want to redirect the script or do something else if the connection doesnt work. But if you just want to display the error message and stop the script then you dont need it, the uncaught exception turns into a fatal error. Or you can use a site-wide error handling setting as well.
Hope that helps
From PHP: Exceptions - Manual:
As of PHP 7.1.0, a catch block may specify multiple exceptions using the pipe (|) character. This is useful for when different exceptions from different class hierarchies are handled the same.
try {
// do something
} catch (Error | Exception $e) {
echo $e->getMessage();
}
Exceptions are thrown intentionally by code using a throw, errors... not so much.
Errors come about as a result of something which isn't handled typically. (IO errors, TCP/IP errors, null reference errors)
I intend to give you a most unusual discussion of error control.
I built a very good error handler into a language years ago, and though some of the names have changed, the principles of error processing are the same today. I had a custom built multi-tasking OS and had to be able to recover from data errors at all levels with no memory leaks, stack growth or crashes. So what follows is my understanding of how errors and exceptions must operate and how they differ. I will just say I do not have an understanding of how the internals of try catch works, so am guessing to some measure.
The first thing that happens under the covers for error processing is jumping from one program state to another. How is that done? I'll get to that.
Historically, errors are older and simpler, and exceptions are newer and a bit more complex and capable. Errors work fine until you need to bubble them up, which is the equivalent of handing a difficult problem to your supervisor.
Errors can be numbers, like error numbers, and sometimes with one or more associated strings. For example if a file-read error occurs you might be able to report what it is and possibly gracefully fail. (Hay, it's a step up from just crashing like in the old days.)
What is not often said about exceptions is that exceptions are objects layered on a special exception stack. It's like a return stack for program flow, but it holds a return state just for error trys and catches. (I used to call them ePush and ePop, and ?Abort was a conditional throw which would ePop and recover to that level, while Abort was a full die or exit.)
On the bottom of the stack is the information about the initial caller, the object that knows about the state when the outer try was started, which is often when your program was started. On top that, or the next layer on the stack, with up being the children, and down being the parents, is the exception object of the next inner try/catch block.
If you put a try inside a try you are stacking the inner try on top of the outer try. When an error occurs in the inner try and either the inner catch can't handle it or the error is thrown to the outer try, then control is passed to the outer catch block (object) to see if it can handle the error, i.e. your supervisor.
So what this error stack really does is to be able to mark and restore program flow and system state, in other words, it allows a program to not crash the return stack and mess up things for others (data) when things go wrong. So it also saves the state of any other resources like memory allocation pools and so it can clean them up when catch is done. In general this can be a very complicated thing, and that is why exception handling is often slow. In general quite a bit of state needs to go into these exception blocks.
So a try/catch block sort of sets a state to be able to return to if all else gets messed up. It's like a parent. When our lives get messed up we can fall back into our parent's lap and they will make it all right again.
Hope I didn't disappoint you.
Once set_error_handler() is defined, error handler is similar to Exception's. See code below:
<?php
function handleErrors( $e_code ) {
echo "error code: " . $e_code . "<br>";
}
set_error_handler( "handleErrors" );
trigger_error( "trigger a fatal error", E_USER_ERROR);
echo "after error."; //it would run if set_error_handler is defined, otherwise, it wouldn't show
?>
You may add this comment
function doSomething()
{
/** #noinspection PhpUnhandledExceptionInspection */
throw new Exception();
}

In PHP, how can I detect that input vars were truncated due to max_input_vars being exceeded?

I know that an E_WARNING is generated by PHP
PHP Warning: Unknown: Input variables exceeded 1000
But how can I detect this in my script?
A "close enough" method would be to check if( count($_POST, COUNT_RECURSIVE) == ini_get("max_input_vars"))
This will cause a false positive if the number of POST vars happens to be exactly on the limit, but considering the default limit is 1000 it's unlikely to ever be a concern.
count($_POST, COUNT_RECURSIVE) is not accurate because it counts all nodes in the array tree whereas input_vars are only the terminal nodes. For example, $_POST['a']['b'] = 'c' has 1 input_var but using COUNT_RECURSIVE will return 3.
php://input cannot be used with enctype="multipart/form-data". http://php.net/manual/en/wrappers.php.php
Since this issue only arises with PHP >= 5.3.9, we can use anonymous functions. The following recursively counts the terminals in an array.
function count_terminals($a) {
return is_array($a)
? array_reduce($a, function($carry, $item) {return $carry + count_terminals($item);}, 0)
: 1;
}
What works for me is this. Firstly, I put this at the top of my script/handler/front controller. This is where the error will be saved (or $e0 will be null, which is OK).
$e0 = error_get_last();
Then I run a bunch of other processing, bootstrapping my application, registering plugins, establishing sessions, checking database state - lots of things - that I can accomplish regardless of exceeding this condition.. Then I check this $e0 state. If it's not null, we have an error so I bail out (assume that App is a big class with lots of your magic in it)
if (null != $e0) {
ob_end_clean(); // Purge the outputted Warning
App::bail($e0); // Spew the warning in a friendly way
}
Tweak and tune error handlers for your own state.
Registering an error handler won't catch this condition because it exists before your error handler is registered.
Checking input var count to equal the maximum is not reliable.
The above $e0 will be an array, with type => 8, and line => 0; the message will explicitly mention input_vars so you could regex match to create a very narrow condition and ensure positive identification of the specific case.
Also note, according to the PHP specs this is a Warning not an Error.
function checkMaxInputVars()
{
$max_input_vars = ini_get('max_input_vars');
# Value of the configuration option as a string, or an empty string for null values, or FALSE if the configuration option doesn't exist
if($max_input_vars == FALSE)
return FALSE;
$php_input = substr_count(file_get_contents('php://input'), '&');
$post = count($_POST, COUNT_RECURSIVE);
echo $php_input, $post, $max_input_vars;
return $php_input > $post;
}
echo checkMaxInputVars() ? 'POST has been truncated.': 'POST is not truncated.';
Call error_get_last() as soon as possible in your script (before you have a chance to cause errors, as they will obscure this one.) In my testing, the max_input_vars warning will be there if applicable.
Here is my test script with max_input_vars set to 100:
<?php
if (($error = error_get_last()) !== null) {
echo 'got error:';
var_dump($error);
return;
}
unset($error);
if (isset($_POST['0'])) {
echo 'Got ',count($_POST),' vars';
return;
}
?>
<form method="post">
<?php
for ($i = 0; $i < 200; $i++) {
echo '<input name="',$i,'" value="foo" type="hidden">';
}
?>
<input type="submit">
</form>
Output when var limit is hit:
got error:
array
'type' => int 2
'message' => string 'Unknown: Input variables exceeded 100. To increase the limit change max_input_vars in php.ini.' (length=94)
'file' => string 'Unknown' (length=7)
'line' => int 0
Tested on Ubuntu with PHP 5.3.10 and Apache 2.2.22.
I would be hesitant to check explicitly for this error string, for stability (they could change it) and general PHP good practice. I prefer to turn all PHP errors into exceptions, like this (separate subclasses may be overkill, but I like this example because it allows # error suppression.) It would be a little different coming from error_get_last() but should be pretty easy to adapt.
I don't know if there are other pre-execution errors that could get caught by this method.
What about something like that:
$num_vars = count( explode( '###', http_build_query($array, '', '###') ) );
You can repeat it both for $_POST, $_GET, $_COOKIE, whatever.
Still cant be considered 100% accurate, but I guess it get pretty close to it.

Throwing errors from its "correct" source

I hope the title isn't too confusing, I'll try to explain better below.
Suppose I have a function in a separate file, functions.php:
function divide($num1, $num2) {
if ($num1 == 0 || $num2 == 0) {
trigger_error("Cannot divide by 0", E_USER_ERROR);
} else {
return ($num1 / $num2);
}
}
And another file that calls it:
include "functions.php";
echo divide(10, 0);
My error is
Fatal error: Cannot divide by 0 in
C:\Users\Derek\Desktop\projects\functions.php on line 5
My question is, how do I make that error instead point to the location of the error in the main code, so I instead get:
Fatal error: Cannot divide by 0 in
C:\Users\Derek\Desktop\projects\main.php on line 3
The particular reason I want this is because I have a function called load_class that simply finds a PHP file and instantiates the object inside, but if given an incorrect file name, it reports an error from inside load_class, which is technically true, but it's not particularly helpful if I don't remember where I called load_class in the first place. I would like the error to point to the file that called load_class incorrectly.
Also, I would like to write a function error() (something like below) that when given a message as a parameter would throw more "meaningful" error messages, but when done that way, the error always says it comes from error(), not from where the error actually came from!
For example, in an error.php:
/**
* error()
*
* Throws an error of a certain type
*
* #param string $type The type of error. "Fatal", "warning," or "notice"
* #param string $message A description of the error
* #return void
*/
function error($type, $message) {
switch (strtolower($type)) {
case 'fatal':
trigger_error($message, E_USER_ERROR);
break;
case 'notice':
trigger_error($message, E_USER_NOTICE);
default:
trigger_error($message, E_USER_WARNING);
break;
}
}
And in an index.php
error("fatal", "A sample warning!");
My error given is:
Fatal error: A sample warning! in
C:\Users\Derek\Desktop\projects\synthesis\sys\Error.php on line 45
But the error didn't occur in error.php, it happened in index.php! How can I make it show where it really came from?
The debug_backtrace function allows you to obtain the stacktrace as an array. You can pick the original location from there.
Next to that you need to slip into the error message to make this look-alike. Example:
function divide($num1, $num2) {
if ($num1 == 0 || $num2 == 0) {
trigger_error_original("Cannot divide by 0", E_USER_ERROR);
} else {
return ($num1 / $num2);
}
}
function trigger_error_original($message, $type) {
$trace = debug_backtrace(FALSE);
list($location) = array_slice($trace, 1, 1) + array('file' => 'unknown', 'line' => 'unknown');
$message .= sprintf(" in %s on line %d\nTriggered", $location['file'], $location['line']);
trigger_error($message, $type);
}
divide(1, 0);
The error message than shows something like:
> php test-pad.php
Fatal error: Cannot divide by 0 in test-pad.php on line 18
Triggered in test-pad.php on line 15
The downside of this is, that you need to change your code to have this "feature". If you need this for debugging your own code, it's much better that you enable backtraces in your logs. The Xdebug extension does this for you, or you can write your own error handler that takes care of that.
See as well the related question Caller function in PHP 5?. I used array_slice so that you could create an additional parameter to define the number of steps you want to go "up" in the backtrace.
Use debug_backtrace(), and debug_print_backtrace() for a full call stack. These are especially effective when using Xdebug, which will override the function to colorize the output.
I have this same problem...
#1: while 10/0 = ERROR, 0/10 = 0 is perfectly legal, you shouldn't have an exception for that.
#2: when you include a file, it effectively becomes part of this new file, so perhaps you might have to toy a little bit with things like __FILE__ and see if you can make it point it to the file before it gets included in the other file..
You can use xdebug - it will show you the stacktrace or you can register your own error handndler and display the stacktrace. Just check the example in php.net for set_error_handler().
Maybe exceptions are better to use in your case. You get the full stacktrace and can locate where the function was called without relying on some tricky code :)

Objects and error handling in PHP

What's the best practice to handle errors if using objects?
A) Before the method of object is called and not even getting to execute method if there's some error, or
B) Just pass parameters and perform error checking in method itself, returning error code or something.
Please pick your option and short description, why?
Thanks orlandu63, it is good practice, but what about non-fatal errors, such as user should provide a title for something, and he/she didn't?
class Sample {
var $err_no_title = 1;
function createNewRecord ($title) {
if (!$title) return $this->err_no_title;
}
}
Or use exceptions for these kind of errors also?
If you're using OO, you might as well use Exceptions. My answer is a mix of both A and B:
class DatabaseConnectionException extends Exception {}
class Database {
public function connect($user, $pass, $db) {
//Connection stuff.
if($baduser) {
throw new DatabaseConnectionException('Username (' . $user. ') is invalid.')
}
if($badpass) {
//''
}
}
}
$db = new Database;
try {
$db->connect($user, $pass, $db);
catch (DatabaseConnectionException $e) {
die('I cannot connect to the database:' . $e);
}
What are the advantages to this? I don't know, but it seems right.
You can read more on it on http://php.net/exceptions and google.
Regarding your second part,
First of all your example will treat it more of an error than a "warning" since you exit the function and thus don't create a record if you have no title. This shows that method B is flawed. So method A all the way.
To choose from options you offer it would be B, but don't use error codes and throw exceptions instead. All the logic (even validation of inputs) should be encapsulated in the function.
The reasons are:
The function may change and so may change requirements for inputs.
User of your function may not always know, what the inputs should be like.
You surely don't want to repeat the validation code everywhere you use the function.
Be careful though, as exceptions are raised by object oriented code only. For example this code does not fire an exception:
<?php
$number = $number / 0;
?>
Your example would be like:
<?php
class Sample {
function createNewRecord ($title) {
if (!$title) throw new Exception('Title required');
}
}
...
try {
$mysample->createNewRecord($title);
} catch ($ex) {
echo "Could not create record. Please try again. (Reason: $ex)";
}
...
?>
In the first place, this sort of thing should be validated in the user interface. So it would be A, but B needs to be there to. So final verdict would be: both.

Categories