php OOP Exceptions or die()? - php

I am developing some project. And I want to control different errors. I know that in all popular frameworks and php projects there are different Exceptions. But I think that is not required work. If the error is occured we can make die() with our message.
1. What are the main pluses of Exceptions?
2. Can I control my errors with die()?
Thank you.

Well, you could use die(). But that makes all errors fatal. Meaning that you cannot try to recover from the error at all. In some cases that's fine to do.
But in most cases, you may want the ability to "clean up" after the error, or to try another method. This is where exceptions come in handy... They let you chose where and if you want to handle the error. They let you try to gracefully recover from the errors.
For example, let's say you have a method which downloads a file from a remote server: downloadFromRemoteServer($address);
If you use die(), if the download fails, the script terminates. End of story.
But if you use exceptions, you could try another server or even try a different method (HTTP vs FTP, etc):
try {
$file = downloadFromRemoteServer('http://example.com/foo');
} catch (DownloadFailedException $e) {
try {
$file = downloadFromRemoteServer('http://secondtry.example.com/foo');
} catch (DownloadFailedException $e2) {
die('Could not download file');
}
}
return $file;
But remember that Exceptions are useful only for exceptional circumstances. They are not meant to be used for any possible error. For example, if a user doesn't verify their email address correctly, that's not exceptional. But if you can't connect to the database server, or have a conflict in the DB, that would be an exception circumstance...

Alexander,
die() and Exceptions accomplish different things.
the "die" language construct just halts the execution of a script and possibly outputs the parameters if it has been called like a function.
On the other hand, exceptions are more advanced structures that are used in OOP contexts to give the developer more flexibility as to whether a script needs to be stopped and if so, in what manner, what output to be shown to the user etc.
Exceptions are a little bit more complex than this so you should perhaps document yourself with some OOP first or for that matter read about zend framework and you'll get a grasp of what Exceptions are.
For simple stuff though, you can always use exit (or die, which is the same thing).
I hope this helps,
Slavic

1 What are the main pluses of Exceptions?
The main advantages are:
failing functions don't have to pollute their return with error conditions
typed exceptions can be handled at appropriate levels in the code, you decide which portion of the code can handle which errors
you can store a lot more information about the error condition in the exception itself, making handling it, and possibly recovering from it, easier.
2 Can I control my errors with die()?
I'd hardly call it control, I'd call it giving up on actually handling an error. At no point in my projects is a die() actually user-friendly, and all those die('...some error condition...'); examples of PHP code are IMHO only suited for projects in development. In production, you'll want your users to be able to continue their tasks / programs in the easiest way possible, so a 'try again' (if error condition is not likely to be met again), 'sorry that doesn't work' / other kinds of messages, forms / pages are all more desirable then die().

Related

PHP error handling working in MySQL & MySQLi but not PDO

I've just finished refactoring a bunch of MySQL and MySQLi forms to PDO.
Everything seems to be working.
Now on to error handling.
In the MySQL / MySQLi code I had been using if statements to catch errors. Like this:
if (!$database_connection) {
// error handling here
}
Plain and simple.
But I can't get a similar set-up to work with PDO.
Here's the scenario:
I have a connection to a database that looks something like this:
$data_source_name = "mysql:host=$db_host;dbname=$db_name";
$database_connection = new PDO($data_source_name, $db_username, $db_password);
The execution looks something like this:
$stmt= $database_connection->prepare($sql);
$stmt->execute([$name, $email]);
I'm trying to set up a condition like the one described above:
if ( database connection fails ) {
// error handling
}
But this code doesn't work.
if ( !$database_connection ) {
// error handling
} else {
$stmt= $database_connection->prepare($sql);
$stmt->execute([$name, $email]);
}
This if construct worked in MySQL (now deprecated) and works in MySQLi, but not PDO.
I was originally trying to make this work using try-catch, as recommended in many Stack posts. But after more research it appears that this function is inappropriate for PDO Exceptions.
Any guidance and suggestions appreciated. Thanks.
It's a very common fallacy, that one needs a dedicated error handling code for PDO or Mysqli (or whatever else module for that matter). Least it should be even more specific, such as "Mysqli connection" handler, as it seems with your old mysqli code.
If you think of it, you don't really care whether it was exactly a database error that prevented the code form being executed correctly. There can be any other problem as well.
Admittedly, one hardly can expect any other problem from such a simple code but still, the code may grow, become more modular, perform more tasks - and therefore error out in any other part as well. Like, writing database credentials in the every file is a bit of waste. So it's natural to put them in a file and then just include it in the every other script that requires a database interaction. So this file may get corrupted which will has the same effect as a database error. And will need to be fixed as well.
Or, if you're handling only the connection error, the problem can happen during the query execution as well (especially in your case, as the way the query is executed it will error out even if a customer will simply enter fish'h'chips for example).
What you really care for is whether the data has been stored correctly (and probably whether emails were sent as well) or not, no matter what could be the possible failure. This is being the exact reason, why I wrote in the article this warning against wrapping some specific part of code in a try-catch in order to report this particular error. As error reporting handler must be common for the entire code.
Admittedly, the simplest exception handling method is simply wrapping the entire code in a try catch block where the most generic exception type, namely Throwable, must be checked for. Not very reliable but simplest.
The key here is to wrap the entire code, not just some random part of it. But one shouldn't forget to set the exception mode for PDO, in order let the query execution errors to be caught in this block as well.
<?php
try {
require 'pdo.php'
...
$sql = "INSERT INTO other_choices (order,foods) VALUES (?,?)";
...
$stmt= $db_connection->prepare($sql);
$stmt->execute([$order, $foods]);
// send emails, etc
} catch (Throwable $e) {
// do your handling here
}
Note that I substituted actual variables in the query with question marks, which is being correct way of using prepared statements, that otherwise become useless and render all your transition from mysqli fruitless (especially given that mysqli supports prepared statements as well).
Unfortunately, PHP has two kinds of errors - exceptions and errors proper. And try-catch can catch only the former. In order to handle all kinds of errors, an error handler can be used. You can see a very basic example of one in my article on PHP error reporting.
The last note: sending an email every time an error occurs on the site is not the wisest move. Although in your case it could be justified, given PHP is only involved when a user submits a form, but on a regular site, where PHP is used to handle every page, it can lead to thousands emails. Or even in your case, spammers may target your forms and send thousands requests as well (which itself may cause some overflow error and therefore thousands emails in the inbox). Instead of sending emails manually, consider using a dedicated error monitoring software, such as Sentry. It will send only new errors, as well as aggregated error info.
new PDO raises an exception if the connection fails. Use an exception handler:
try {
$database_connection = new PDO($data_source_name, $db_username, $db_password);
} catch (PDOException $e) {
// error handling
}

What exactly does the # symbol in front of new mean? [duplicate]

In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
If so, in what circumstances would you use this?
Code examples are welcome.
Edit: Note to repliers. I'm not looking to turn error reporting off, but, for example, common practice is to use
#fopen($file);
and then check afterwards... but you can get rid of the # by doing
if (file_exists($file))
{
fopen($file);
}
else
{
die('File not found');
}
or similar.
I guess the question is - is there anywhere that # HAS to be used to supress an error, that CANNOT be handled in any other manner?
Note: Firstly, I realise 99% of PHP developers use the error suppression operator (I used to be one of them), so I'm expecting any PHP dev who sees this to disagree.
In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
Short answer:
No!
Longer more correct answer:
I don't know as I don't know everything, but so far I haven't come across a situation where it was a good solution.
Why it's bad:
In what I think is about 7 years using PHP now I've seen endless debugging agony caused by the error suppression operator and have never come across a situation where it was unavoidable.
The problem is that the piece of code you are suppressing errors for, may currently only cause the error you are seeing; however when you change the code which the suppressed line relies on, or the environment in which it runs, then there is every chance that the line will attempt to output a completely different error from the one you were trying to ignore. Then how do you track down an error that isn't outputting? Welcome to debugging hell!
It took me many years to realise how much time I was wasting every couple of months because of suppressed errors. Most often (but not exclusively) this was after installing a third party script/app/library which was error free in the developers environment, but not mine because of a php or server configuration difference or missing dependency which would have normally output an error immediately alerting to what the issue was, but not when the dev adds the magic #.
The alternatives (depending on situation and desired result):
Handle the actual error that you are aware of, so that if a piece of code is going to cause a certain error then it isn't run in that particular situation. But I think you get this part and you were just worried about end users seeing errors, which is what I will now address.
For regular errors you can set up an error handler so that they are output in the way you wish when it's you viewing the page, but hidden from end users and logged so that you know what errors your users are triggering.
For fatal errors set display_errors to off (your error handler still gets triggered) in your php.ini and enable error logging. If you have a development server as well as a live server (which I recommend) then this step isn't necessary on your development server, so you can still debug these fatal errors without having to resort to looking at the error log file. There's even a trick using the shutdown function to send a great deal of fatal errors to your error handler.
In summary:
Please avoid it. There may be a good reason for it, but I'm yet to see one, so until that day it's my opinion that the (#) Error suppression operator is evil.
You can read my comment on the Error Control Operators page in the PHP manual if you want more info.
I would suppress the error and handle it. Otherwise you may have a TOCTOU issue (Time-of-check, time-of-use. For example a file may get deleted after file_exists returns true, but before fopen).
But I wouldn't just suppress errors to make them go away. These better be visible.
Yes suppression makes sense.
For example, the fopen() command returns FALSE if the file cannot be opened. That's fine, but it also produces a PHP warning message. Often you don't want the warning -- you'll check for FALSE yourself.
In fact the PHP manual specifically suggests using # in this case!
If you don't want a warning thrown when using functions like fopen(), you can suppress the error but use exceptions:
try {
if (($fp = #fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
Error suppression should be avoided unless you know you can handle all the conditions.
This may be much harder than it looks at first.
What you really should do is rely on php's "error_log" to be your reporting method, as you cannot rely on users viewing pages to report errors. ( And you should also disable php from displaying these errors )
Then at least you'll have a comprehensive report of all things going wrong in the system.
If you really must handle the errors, you can create a custom error handler
http://php.net/set-error-handler
Then you could possibly send exceptions ( which can be handled ) and do anything needed to report weird errors to administration.
I NEVER allow myself to use '#'... period.
When I discover usage of '#' in code, I add comments to make it glaringly apparent, both at the point of usage, and in the docblock around the function where it is used. I too have been bitten by "chasing a ghost" debugging due to this kind of error suppression, and I hope to make it easier on the next person by highlighting its usage when I find it.
In cases where I'm wanting my own code to throw an Exception if a native PHP function encounters an error, and '#' seems to be the easy way to go, I instead choose to do something else that gets the same result but is (again) glaringly apparent in the code:
$orig = error_reporting(); // capture original error level
error_reporting(0); // suppress all errors
$result = native_func(); // native_func() is expected to return FALSE when it errors
error_reporting($orig); // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }
That's a lot more code that just writing:
$result = #native_func();
but I prefer to make my suppression need VERY OBVIOUS, for the sake of the poor debugging soul that follows me.
Most people do not understand the meaning of error message.
No kidding. Most of them.
They think that error messages are all the same, says "Something goes wrong!"
They don't bother to read it.
While it's most important part of error message - not just the fact it has been raised, but it's meaning. It can tell you what is going wrong. Error messages are for help, not for bothering you with "how to hide it?" problem. That's one of the biggest misunderstandings in the newbie web-programming world.
Thus, instead of gagging error message, one should read what it says. It has not only one "file not found" value. There can be thousands different errors: permission denied, save mode restriction, open_basedir restriction etc.etc. Each one require appropriate action. But if you gag it you'll never know what happened!
The OP is messing up error reporting with error handling, while it's very big difference!
Error handling is for user. "something happened" is enough here.
While error reporting is for programmer, who desperately need to know what certainly happened.
Thus, never gag errors messages. Both log it for the programmer, and handle it for the user.
is there not a way to suppress from the php.ini warnings and errors? in that case you can debug only changing a flag and not trying to discovering which # is hiding the problem.
Using # is sometimes counter productive. In my experience, you should always turn error reporting off in the php.ini or call
error_reporting(0);
on a production site. This way when you are in development you can just comment out the line and keep errors visible for debugging.
One place I use it is in socket code, for example, if you have a timeout set you'll get a warning on this if you don't include #, even though it's valid to not get a packet.
$data_len = #socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
The only place where I really needed to use it is the eval function. The problem with eval is that, when string cannot be parsed due to syntax error, eval does not return false, but rather throws an error, just like having a parse error in the regular script. In order to check whether the script stored in the string is parseable you can use something like:
$script_ok = #eval('return true; '.$script);
AFAIK, this is the most elegant way to do this.
Some functions in PHP will issue an E_NOTICE (the unserialize function for example).
A possible way to catch that error (for PHP versions 7+) is to convert all issued errors into exceptions and not let it issue an E_NOTICE. We could change the exception error handler as follow:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... will throw the exception here
}
Today I encountered an issue that was a good example on when one might want to use at least temporarily the # operator.
Long story made short, I found logon info (username and password in plain text) written into the error log trace.
Here a bit more info about this issue.
The logon logic is in a class of it's own, because the system is supposed to offer different logon mechanisms. Due to server migration issues there was an error occurring. That error dumped the entire trace into the error log, including password info! One method expected the username and password as parameters, hence trace wrote everything faithfully into the error log.
The long term fix here is to refactor said class, instead of using username and password as 2 parameters, for example using a single array parameter containing those 2 values (trace will write out Array for the paramater in such cases). There are also other ways of tackling this issue, but that is an entire different issue.
Anyways. Trace messages are helpful, but in this case were outright harmful.
The lesson I learned, as soon as I noticed that trace output: Sometimes suppressing an error message for the time being is an useful stop gap measure to avoid further harm.
In my opinion I didn't think it is a case of bad class design. The error itself was triggered by an PDOException ( timestamp issue moving from MySQL 5.6 to 5.7 ) that just dumped by PHP default everything into the error log.
In general I do not use the # operator for all the reasons explained in other comments, but in this case the error log convinced me to do something quick until the problem was properly fixed.
You do not want to suppress everything, since it slows down your script.
And yes there is a way both in php.ini and within your script to remove errors (but only do this when you are in a live environment and log your errors from php)
<?php
error_reporting(0);
?>
And you can read this for the php.ini version of turning it off.
I have what I think is a valid use-case for error suppression using #.
I have two systems, one running PHP 5.6.something and another running PHP 7.3.something. I want a script which will run properly on both of them, but some stuff didn't exist back in PHP 5.6, so I'm using polyfills like random_compat.
It's always best to use the built-in functions, so I have code that looks like this:
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else {
#include "random_compat/random.php"; // Suppress warnings+errors
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(4);
} else {
// Boooo! We have to generate crappy randomness
$bytes = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',64)),0,32);
}
}
The fallback to the polyfill should never generate any errors or warnings. I'm checking to see that the function exists after attempting to load the polyfill which is all that is necessary. There is even a fallback to the fallback. And a fallback to the fallback to the fallback.
There is no way to avoid a potential error with include (e.g. using file_exists) so the only way to do it is to suppress warnings and check to see if it worked. At least, in this case.
I can think of one case of use, for auto-increment a non existing array key.
<?php
$totalCars = [];
// suppressing error to avoid a getting a warning error
#$totalCars['toyota']++;
var_export($totalCars);
// array (
// 'toyota' => 1,
// )
// not suppressing error will throw a warning
// but still allows to increase the non-existing key value
$totalCars['ford']++;
var_export($totalCars);
// Warning: Undefined array key "ford"
// array (
// 'toyota' => 1,
// 'ford' => 1,
// )
See this example output here: https://onlinephp.io/c/433f0
If you are using a custom error handling function and wanna suppress an error (probably a known error), use this method. The use of '#' is not a good idea in this context as it will not suppress error if error handler is set.
Write 3 functions and call like this.
# supress error for this statement
supress_error_start();
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.
function supress_error_start(){
set_error_handler('nothing');
error_reporting(0);
}
function supress_error_end(){
set_error_handler('my_err_handler');
error_reporting('Set this to a value of your choice');
}
function nothing(){ #Empty function
}
function my_err_handler('arguments will come here'){
//Your own error handling routines will come here
}
In my experience I would say generally speaking, error suppress is just another bad practice for future developers and should be avoided as much as possible as it hides complication of error and prevent error logging unlike Exception which can help developers with error snapshot. But answering the original question which say "If so, in what circumstances would you use this?".
I would say one should use it against some legacy codes or library that don't throw exception errors but instead handles bad errors by keep the error variables with it's object(speaking of OOP) or using a global variable for logging error or just printing error all together.
Take for example the mysqli object
new mysqli($this->host, $this->username, $this->password, $this->db);
This code above barely or never throw an exception on failed connection, it only store error in mysqli::errno and mysli::error
For modern day coding the one solution I found was to suppress the ugly error messages (which helps no one especially when on production server where debug mode is off) and instead devs should throw their own exception. Which is consider modern practice and help coders track errors more quickly.
$this->connection = #new mysqli($this->host, $this->username, $this->password, $this->db);
if($this->connection->connect_errno)
throw new mysqli_sql_exception($this->connection->error);
You can notice the use of suppression # symbol to prevent the ugly error display should incase error display was turned on development server.
Also I had to throw my own exception. This way I was able to use # symbol and same time I didn't hide error nor did I just make my own guess of what the error could be.
I will say if used rightly, then it is justifiable.
I use it when trying to load an HTML file for processing as a DOMDocument object. If there are any problems in the HTML... and what website doesn't have at least one... DOMDocument->loadHTMLFile() will throw an error if you don't suppress it with #. This is the only way (perhaps there are better ones) I've ever been successful in creating HTML scrapers in PHP.

When would you use '#' expression to mute PHP error messages, rather than just debugging the issue? [duplicate]

In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
If so, in what circumstances would you use this?
Code examples are welcome.
Edit: Note to repliers. I'm not looking to turn error reporting off, but, for example, common practice is to use
#fopen($file);
and then check afterwards... but you can get rid of the # by doing
if (file_exists($file))
{
fopen($file);
}
else
{
die('File not found');
}
or similar.
I guess the question is - is there anywhere that # HAS to be used to supress an error, that CANNOT be handled in any other manner?
Note: Firstly, I realise 99% of PHP developers use the error suppression operator (I used to be one of them), so I'm expecting any PHP dev who sees this to disagree.
In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
Short answer:
No!
Longer more correct answer:
I don't know as I don't know everything, but so far I haven't come across a situation where it was a good solution.
Why it's bad:
In what I think is about 7 years using PHP now I've seen endless debugging agony caused by the error suppression operator and have never come across a situation where it was unavoidable.
The problem is that the piece of code you are suppressing errors for, may currently only cause the error you are seeing; however when you change the code which the suppressed line relies on, or the environment in which it runs, then there is every chance that the line will attempt to output a completely different error from the one you were trying to ignore. Then how do you track down an error that isn't outputting? Welcome to debugging hell!
It took me many years to realise how much time I was wasting every couple of months because of suppressed errors. Most often (but not exclusively) this was after installing a third party script/app/library which was error free in the developers environment, but not mine because of a php or server configuration difference or missing dependency which would have normally output an error immediately alerting to what the issue was, but not when the dev adds the magic #.
The alternatives (depending on situation and desired result):
Handle the actual error that you are aware of, so that if a piece of code is going to cause a certain error then it isn't run in that particular situation. But I think you get this part and you were just worried about end users seeing errors, which is what I will now address.
For regular errors you can set up an error handler so that they are output in the way you wish when it's you viewing the page, but hidden from end users and logged so that you know what errors your users are triggering.
For fatal errors set display_errors to off (your error handler still gets triggered) in your php.ini and enable error logging. If you have a development server as well as a live server (which I recommend) then this step isn't necessary on your development server, so you can still debug these fatal errors without having to resort to looking at the error log file. There's even a trick using the shutdown function to send a great deal of fatal errors to your error handler.
In summary:
Please avoid it. There may be a good reason for it, but I'm yet to see one, so until that day it's my opinion that the (#) Error suppression operator is evil.
You can read my comment on the Error Control Operators page in the PHP manual if you want more info.
I would suppress the error and handle it. Otherwise you may have a TOCTOU issue (Time-of-check, time-of-use. For example a file may get deleted after file_exists returns true, but before fopen).
But I wouldn't just suppress errors to make them go away. These better be visible.
Yes suppression makes sense.
For example, the fopen() command returns FALSE if the file cannot be opened. That's fine, but it also produces a PHP warning message. Often you don't want the warning -- you'll check for FALSE yourself.
In fact the PHP manual specifically suggests using # in this case!
If you don't want a warning thrown when using functions like fopen(), you can suppress the error but use exceptions:
try {
if (($fp = #fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
Error suppression should be avoided unless you know you can handle all the conditions.
This may be much harder than it looks at first.
What you really should do is rely on php's "error_log" to be your reporting method, as you cannot rely on users viewing pages to report errors. ( And you should also disable php from displaying these errors )
Then at least you'll have a comprehensive report of all things going wrong in the system.
If you really must handle the errors, you can create a custom error handler
http://php.net/set-error-handler
Then you could possibly send exceptions ( which can be handled ) and do anything needed to report weird errors to administration.
I NEVER allow myself to use '#'... period.
When I discover usage of '#' in code, I add comments to make it glaringly apparent, both at the point of usage, and in the docblock around the function where it is used. I too have been bitten by "chasing a ghost" debugging due to this kind of error suppression, and I hope to make it easier on the next person by highlighting its usage when I find it.
In cases where I'm wanting my own code to throw an Exception if a native PHP function encounters an error, and '#' seems to be the easy way to go, I instead choose to do something else that gets the same result but is (again) glaringly apparent in the code:
$orig = error_reporting(); // capture original error level
error_reporting(0); // suppress all errors
$result = native_func(); // native_func() is expected to return FALSE when it errors
error_reporting($orig); // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }
That's a lot more code that just writing:
$result = #native_func();
but I prefer to make my suppression need VERY OBVIOUS, for the sake of the poor debugging soul that follows me.
Most people do not understand the meaning of error message.
No kidding. Most of them.
They think that error messages are all the same, says "Something goes wrong!"
They don't bother to read it.
While it's most important part of error message - not just the fact it has been raised, but it's meaning. It can tell you what is going wrong. Error messages are for help, not for bothering you with "how to hide it?" problem. That's one of the biggest misunderstandings in the newbie web-programming world.
Thus, instead of gagging error message, one should read what it says. It has not only one "file not found" value. There can be thousands different errors: permission denied, save mode restriction, open_basedir restriction etc.etc. Each one require appropriate action. But if you gag it you'll never know what happened!
The OP is messing up error reporting with error handling, while it's very big difference!
Error handling is for user. "something happened" is enough here.
While error reporting is for programmer, who desperately need to know what certainly happened.
Thus, never gag errors messages. Both log it for the programmer, and handle it for the user.
is there not a way to suppress from the php.ini warnings and errors? in that case you can debug only changing a flag and not trying to discovering which # is hiding the problem.
Using # is sometimes counter productive. In my experience, you should always turn error reporting off in the php.ini or call
error_reporting(0);
on a production site. This way when you are in development you can just comment out the line and keep errors visible for debugging.
One place I use it is in socket code, for example, if you have a timeout set you'll get a warning on this if you don't include #, even though it's valid to not get a packet.
$data_len = #socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
The only place where I really needed to use it is the eval function. The problem with eval is that, when string cannot be parsed due to syntax error, eval does not return false, but rather throws an error, just like having a parse error in the regular script. In order to check whether the script stored in the string is parseable you can use something like:
$script_ok = #eval('return true; '.$script);
AFAIK, this is the most elegant way to do this.
Some functions in PHP will issue an E_NOTICE (the unserialize function for example).
A possible way to catch that error (for PHP versions 7+) is to convert all issued errors into exceptions and not let it issue an E_NOTICE. We could change the exception error handler as follow:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... will throw the exception here
}
Today I encountered an issue that was a good example on when one might want to use at least temporarily the # operator.
Long story made short, I found logon info (username and password in plain text) written into the error log trace.
Here a bit more info about this issue.
The logon logic is in a class of it's own, because the system is supposed to offer different logon mechanisms. Due to server migration issues there was an error occurring. That error dumped the entire trace into the error log, including password info! One method expected the username and password as parameters, hence trace wrote everything faithfully into the error log.
The long term fix here is to refactor said class, instead of using username and password as 2 parameters, for example using a single array parameter containing those 2 values (trace will write out Array for the paramater in such cases). There are also other ways of tackling this issue, but that is an entire different issue.
Anyways. Trace messages are helpful, but in this case were outright harmful.
The lesson I learned, as soon as I noticed that trace output: Sometimes suppressing an error message for the time being is an useful stop gap measure to avoid further harm.
In my opinion I didn't think it is a case of bad class design. The error itself was triggered by an PDOException ( timestamp issue moving from MySQL 5.6 to 5.7 ) that just dumped by PHP default everything into the error log.
In general I do not use the # operator for all the reasons explained in other comments, but in this case the error log convinced me to do something quick until the problem was properly fixed.
You do not want to suppress everything, since it slows down your script.
And yes there is a way both in php.ini and within your script to remove errors (but only do this when you are in a live environment and log your errors from php)
<?php
error_reporting(0);
?>
And you can read this for the php.ini version of turning it off.
I have what I think is a valid use-case for error suppression using #.
I have two systems, one running PHP 5.6.something and another running PHP 7.3.something. I want a script which will run properly on both of them, but some stuff didn't exist back in PHP 5.6, so I'm using polyfills like random_compat.
It's always best to use the built-in functions, so I have code that looks like this:
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else {
#include "random_compat/random.php"; // Suppress warnings+errors
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(4);
} else {
// Boooo! We have to generate crappy randomness
$bytes = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',64)),0,32);
}
}
The fallback to the polyfill should never generate any errors or warnings. I'm checking to see that the function exists after attempting to load the polyfill which is all that is necessary. There is even a fallback to the fallback. And a fallback to the fallback to the fallback.
There is no way to avoid a potential error with include (e.g. using file_exists) so the only way to do it is to suppress warnings and check to see if it worked. At least, in this case.
I can think of one case of use, for auto-increment a non existing array key.
<?php
$totalCars = [];
// suppressing error to avoid a getting a warning error
#$totalCars['toyota']++;
var_export($totalCars);
// array (
// 'toyota' => 1,
// )
// not suppressing error will throw a warning
// but still allows to increase the non-existing key value
$totalCars['ford']++;
var_export($totalCars);
// Warning: Undefined array key "ford"
// array (
// 'toyota' => 1,
// 'ford' => 1,
// )
See this example output here: https://onlinephp.io/c/433f0
If you are using a custom error handling function and wanna suppress an error (probably a known error), use this method. The use of '#' is not a good idea in this context as it will not suppress error if error handler is set.
Write 3 functions and call like this.
# supress error for this statement
supress_error_start();
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.
function supress_error_start(){
set_error_handler('nothing');
error_reporting(0);
}
function supress_error_end(){
set_error_handler('my_err_handler');
error_reporting('Set this to a value of your choice');
}
function nothing(){ #Empty function
}
function my_err_handler('arguments will come here'){
//Your own error handling routines will come here
}
In my experience I would say generally speaking, error suppress is just another bad practice for future developers and should be avoided as much as possible as it hides complication of error and prevent error logging unlike Exception which can help developers with error snapshot. But answering the original question which say "If so, in what circumstances would you use this?".
I would say one should use it against some legacy codes or library that don't throw exception errors but instead handles bad errors by keep the error variables with it's object(speaking of OOP) or using a global variable for logging error or just printing error all together.
Take for example the mysqli object
new mysqli($this->host, $this->username, $this->password, $this->db);
This code above barely or never throw an exception on failed connection, it only store error in mysqli::errno and mysli::error
For modern day coding the one solution I found was to suppress the ugly error messages (which helps no one especially when on production server where debug mode is off) and instead devs should throw their own exception. Which is consider modern practice and help coders track errors more quickly.
$this->connection = #new mysqli($this->host, $this->username, $this->password, $this->db);
if($this->connection->connect_errno)
throw new mysqli_sql_exception($this->connection->error);
You can notice the use of suppression # symbol to prevent the ugly error display should incase error display was turned on development server.
Also I had to throw my own exception. This way I was able to use # symbol and same time I didn't hide error nor did I just make my own guess of what the error could be.
I will say if used rightly, then it is justifiable.
I use it when trying to load an HTML file for processing as a DOMDocument object. If there are any problems in the HTML... and what website doesn't have at least one... DOMDocument->loadHTMLFile() will throw an error if you don't suppress it with #. This is the only way (perhaps there are better ones) I've ever been successful in creating HTML scrapers in PHP.

How to gracefully die?

So I've just read Why to never use 'or die'.
I am more confused then ever. I am validating a complicated form and I go though many nested levels of if statements and what not and I am passing a variable to the form which is called $status which can only be 'new' or 'edit'. Then when the user submits the form to be validated again the form passes along the $status value as a hidden field ($_POST). I want to make sure that the user cannot accidentally change this so I want to catch the error should something other than 'new' or 'edit' pass though. (Although I would like to completely eliminate the possibility of the user affecting this variable in an ideal world.)
So I figured that I would use DIE() in an if statement
<nested ifs>
Select ($status){
Case 'edit':
break;
Case 'new':
break;
default:
//using example from article
trigger_error("An error that should not occur has occurred", E_USER_ERROR);
break;
}
</nested ifs>
I don't really understand how this is cleaner than die()? Essentially I would like to call another function which displays the user some options of what they can do at this juncture to fix the error, but I want the code to absolutely stop running as I don't want an if statement further down to continue parsing anything and generating an error when it finds something other than 'new' or 'edit'.
I'm not sure how clear I am so please feel free to ask me to elaborate on any unclear points.
(or better yet, can a hidden user field get hacked? How to prevent? :P)
trigger_error() triggers an error which is handled by an error handler.
With trigger_error() you can gracefully handle errors, for example:
set_error_handler('ErrorHandler');
function ErrorHandler($errno, $errmsg, $filename, $linenum, $vars)
{
print '<pre style="line-height: 2em;">';
printf("==> Error in `%s' line %s: %s\n\n", $filename, $linenum, $errmsg);
debug_print_backtrace();
print '</pre>';
exit($errno);
}
This is a simple example, but our company website displays a friendly error page and sends me an email that I'm an idiot and messed up somewhere :-)
The advantage over die() or exit() should be clear :-)
exit() can still be used when you need to exit. For example when you generate a template, output that, and want code execution to stop. Or when you send a header('Location: ...'); header and want to make sure the execution stops ... Just don't use it for handling unexpected situations (i.e. errors).
trigger_error() also gives you a better degree of control. You can send E_USER_NOTICE when you want execution to stop but display a notice, and E_USER_ERROR when you want execution to stop.
In addition, you can write more complex error handler functions where some IP's see a error, and the rest do not ... Kindda useful for development.
Be a but careful with overly complicated error handlers though, what happens is an error occurs inside an error handler ... ? You may have seen Inception :)
The article you linked to explains why you shouldn't use or die, as in:
$result = mysql_query($query) or die('A MySQL query occurred: ' . mysql_error());
Obviously this is a bad idea, as it could output sensitive information about your MySQL structure to a malicious user.
However, I think there is nothing wrong (and I think the writer of the article would agree with me) to use die in the way you are using it, although presenting the user with a list of options would, indeed, be the preferred way to handle this.

Suppress error with # operator in PHP

In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
If so, in what circumstances would you use this?
Code examples are welcome.
Edit: Note to repliers. I'm not looking to turn error reporting off, but, for example, common practice is to use
#fopen($file);
and then check afterwards... but you can get rid of the # by doing
if (file_exists($file))
{
fopen($file);
}
else
{
die('File not found');
}
or similar.
I guess the question is - is there anywhere that # HAS to be used to supress an error, that CANNOT be handled in any other manner?
Note: Firstly, I realise 99% of PHP developers use the error suppression operator (I used to be one of them), so I'm expecting any PHP dev who sees this to disagree.
In your opinion, is it ever valid to use the # operator to suppress an error/warning in PHP whereas you may be handling the error?
Short answer:
No!
Longer more correct answer:
I don't know as I don't know everything, but so far I haven't come across a situation where it was a good solution.
Why it's bad:
In what I think is about 7 years using PHP now I've seen endless debugging agony caused by the error suppression operator and have never come across a situation where it was unavoidable.
The problem is that the piece of code you are suppressing errors for, may currently only cause the error you are seeing; however when you change the code which the suppressed line relies on, or the environment in which it runs, then there is every chance that the line will attempt to output a completely different error from the one you were trying to ignore. Then how do you track down an error that isn't outputting? Welcome to debugging hell!
It took me many years to realise how much time I was wasting every couple of months because of suppressed errors. Most often (but not exclusively) this was after installing a third party script/app/library which was error free in the developers environment, but not mine because of a php or server configuration difference or missing dependency which would have normally output an error immediately alerting to what the issue was, but not when the dev adds the magic #.
The alternatives (depending on situation and desired result):
Handle the actual error that you are aware of, so that if a piece of code is going to cause a certain error then it isn't run in that particular situation. But I think you get this part and you were just worried about end users seeing errors, which is what I will now address.
For regular errors you can set up an error handler so that they are output in the way you wish when it's you viewing the page, but hidden from end users and logged so that you know what errors your users are triggering.
For fatal errors set display_errors to off (your error handler still gets triggered) in your php.ini and enable error logging. If you have a development server as well as a live server (which I recommend) then this step isn't necessary on your development server, so you can still debug these fatal errors without having to resort to looking at the error log file. There's even a trick using the shutdown function to send a great deal of fatal errors to your error handler.
In summary:
Please avoid it. There may be a good reason for it, but I'm yet to see one, so until that day it's my opinion that the (#) Error suppression operator is evil.
You can read my comment on the Error Control Operators page in the PHP manual if you want more info.
I would suppress the error and handle it. Otherwise you may have a TOCTOU issue (Time-of-check, time-of-use. For example a file may get deleted after file_exists returns true, but before fopen).
But I wouldn't just suppress errors to make them go away. These better be visible.
Yes suppression makes sense.
For example, the fopen() command returns FALSE if the file cannot be opened. That's fine, but it also produces a PHP warning message. Often you don't want the warning -- you'll check for FALSE yourself.
In fact the PHP manual specifically suggests using # in this case!
If you don't want a warning thrown when using functions like fopen(), you can suppress the error but use exceptions:
try {
if (($fp = #fopen($filename, "r")) == false) {
throw new Exception;
} else {
do_file_stuff();
}
} catch (Exception $e) {
handle_exception();
}
Error suppression should be avoided unless you know you can handle all the conditions.
This may be much harder than it looks at first.
What you really should do is rely on php's "error_log" to be your reporting method, as you cannot rely on users viewing pages to report errors. ( And you should also disable php from displaying these errors )
Then at least you'll have a comprehensive report of all things going wrong in the system.
If you really must handle the errors, you can create a custom error handler
http://php.net/set-error-handler
Then you could possibly send exceptions ( which can be handled ) and do anything needed to report weird errors to administration.
I NEVER allow myself to use '#'... period.
When I discover usage of '#' in code, I add comments to make it glaringly apparent, both at the point of usage, and in the docblock around the function where it is used. I too have been bitten by "chasing a ghost" debugging due to this kind of error suppression, and I hope to make it easier on the next person by highlighting its usage when I find it.
In cases where I'm wanting my own code to throw an Exception if a native PHP function encounters an error, and '#' seems to be the easy way to go, I instead choose to do something else that gets the same result but is (again) glaringly apparent in the code:
$orig = error_reporting(); // capture original error level
error_reporting(0); // suppress all errors
$result = native_func(); // native_func() is expected to return FALSE when it errors
error_reporting($orig); // restore error reporting to its original level
if (false === $result) { throw new Exception('native_func() failed'); }
That's a lot more code that just writing:
$result = #native_func();
but I prefer to make my suppression need VERY OBVIOUS, for the sake of the poor debugging soul that follows me.
Most people do not understand the meaning of error message.
No kidding. Most of them.
They think that error messages are all the same, says "Something goes wrong!"
They don't bother to read it.
While it's most important part of error message - not just the fact it has been raised, but it's meaning. It can tell you what is going wrong. Error messages are for help, not for bothering you with "how to hide it?" problem. That's one of the biggest misunderstandings in the newbie web-programming world.
Thus, instead of gagging error message, one should read what it says. It has not only one "file not found" value. There can be thousands different errors: permission denied, save mode restriction, open_basedir restriction etc.etc. Each one require appropriate action. But if you gag it you'll never know what happened!
The OP is messing up error reporting with error handling, while it's very big difference!
Error handling is for user. "something happened" is enough here.
While error reporting is for programmer, who desperately need to know what certainly happened.
Thus, never gag errors messages. Both log it for the programmer, and handle it for the user.
is there not a way to suppress from the php.ini warnings and errors? in that case you can debug only changing a flag and not trying to discovering which # is hiding the problem.
Using # is sometimes counter productive. In my experience, you should always turn error reporting off in the php.ini or call
error_reporting(0);
on a production site. This way when you are in development you can just comment out the line and keep errors visible for debugging.
One place I use it is in socket code, for example, if you have a timeout set you'll get a warning on this if you don't include #, even though it's valid to not get a packet.
$data_len = #socket_recvfrom( $sock, $buffer, 512, 0, $remote_host, $remote_port )
The only place where I really needed to use it is the eval function. The problem with eval is that, when string cannot be parsed due to syntax error, eval does not return false, but rather throws an error, just like having a parse error in the regular script. In order to check whether the script stored in the string is parseable you can use something like:
$script_ok = #eval('return true; '.$script);
AFAIK, this is the most elegant way to do this.
Some functions in PHP will issue an E_NOTICE (the unserialize function for example).
A possible way to catch that error (for PHP versions 7+) is to convert all issued errors into exceptions and not let it issue an E_NOTICE. We could change the exception error handler as follow:
function exception_error_handler($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
}
set_error_handler('exception_error_handler');
try {
unserialize('foo');
} catch(\Exception $e) {
// ... will throw the exception here
}
Today I encountered an issue that was a good example on when one might want to use at least temporarily the # operator.
Long story made short, I found logon info (username and password in plain text) written into the error log trace.
Here a bit more info about this issue.
The logon logic is in a class of it's own, because the system is supposed to offer different logon mechanisms. Due to server migration issues there was an error occurring. That error dumped the entire trace into the error log, including password info! One method expected the username and password as parameters, hence trace wrote everything faithfully into the error log.
The long term fix here is to refactor said class, instead of using username and password as 2 parameters, for example using a single array parameter containing those 2 values (trace will write out Array for the paramater in such cases). There are also other ways of tackling this issue, but that is an entire different issue.
Anyways. Trace messages are helpful, but in this case were outright harmful.
The lesson I learned, as soon as I noticed that trace output: Sometimes suppressing an error message for the time being is an useful stop gap measure to avoid further harm.
In my opinion I didn't think it is a case of bad class design. The error itself was triggered by an PDOException ( timestamp issue moving from MySQL 5.6 to 5.7 ) that just dumped by PHP default everything into the error log.
In general I do not use the # operator for all the reasons explained in other comments, but in this case the error log convinced me to do something quick until the problem was properly fixed.
You do not want to suppress everything, since it slows down your script.
And yes there is a way both in php.ini and within your script to remove errors (but only do this when you are in a live environment and log your errors from php)
<?php
error_reporting(0);
?>
And you can read this for the php.ini version of turning it off.
I have what I think is a valid use-case for error suppression using #.
I have two systems, one running PHP 5.6.something and another running PHP 7.3.something. I want a script which will run properly on both of them, but some stuff didn't exist back in PHP 5.6, so I'm using polyfills like random_compat.
It's always best to use the built-in functions, so I have code that looks like this:
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else {
#include "random_compat/random.php"; // Suppress warnings+errors
if(function_exists("random_bytes")) {
$bytes = random_bytes(32);
} else if(function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes(4);
} else {
// Boooo! We have to generate crappy randomness
$bytes = substr(str_shuffle(str_repeat('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',64)),0,32);
}
}
The fallback to the polyfill should never generate any errors or warnings. I'm checking to see that the function exists after attempting to load the polyfill which is all that is necessary. There is even a fallback to the fallback. And a fallback to the fallback to the fallback.
There is no way to avoid a potential error with include (e.g. using file_exists) so the only way to do it is to suppress warnings and check to see if it worked. At least, in this case.
I can think of one case of use, for auto-increment a non existing array key.
<?php
$totalCars = [];
// suppressing error to avoid a getting a warning error
#$totalCars['toyota']++;
var_export($totalCars);
// array (
// 'toyota' => 1,
// )
// not suppressing error will throw a warning
// but still allows to increase the non-existing key value
$totalCars['ford']++;
var_export($totalCars);
// Warning: Undefined array key "ford"
// array (
// 'toyota' => 1,
// 'ford' => 1,
// )
See this example output here: https://onlinephp.io/c/433f0
If you are using a custom error handling function and wanna suppress an error (probably a known error), use this method. The use of '#' is not a good idea in this context as it will not suppress error if error handler is set.
Write 3 functions and call like this.
# supress error for this statement
supress_error_start();
$mail_sent = mail($EmailTo, $Subject, $message,$headers);
supress_error_end(); #Don't forgot to call this to restore error.
function supress_error_start(){
set_error_handler('nothing');
error_reporting(0);
}
function supress_error_end(){
set_error_handler('my_err_handler');
error_reporting('Set this to a value of your choice');
}
function nothing(){ #Empty function
}
function my_err_handler('arguments will come here'){
//Your own error handling routines will come here
}
In my experience I would say generally speaking, error suppress is just another bad practice for future developers and should be avoided as much as possible as it hides complication of error and prevent error logging unlike Exception which can help developers with error snapshot. But answering the original question which say "If so, in what circumstances would you use this?".
I would say one should use it against some legacy codes or library that don't throw exception errors but instead handles bad errors by keep the error variables with it's object(speaking of OOP) or using a global variable for logging error or just printing error all together.
Take for example the mysqli object
new mysqli($this->host, $this->username, $this->password, $this->db);
This code above barely or never throw an exception on failed connection, it only store error in mysqli::errno and mysli::error
For modern day coding the one solution I found was to suppress the ugly error messages (which helps no one especially when on production server where debug mode is off) and instead devs should throw their own exception. Which is consider modern practice and help coders track errors more quickly.
$this->connection = #new mysqli($this->host, $this->username, $this->password, $this->db);
if($this->connection->connect_errno)
throw new mysqli_sql_exception($this->connection->error);
You can notice the use of suppression # symbol to prevent the ugly error display should incase error display was turned on development server.
Also I had to throw my own exception. This way I was able to use # symbol and same time I didn't hide error nor did I just make my own guess of what the error could be.
I will say if used rightly, then it is justifiable.
I use it when trying to load an HTML file for processing as a DOMDocument object. If there are any problems in the HTML... and what website doesn't have at least one... DOMDocument->loadHTMLFile() will throw an error if you don't suppress it with #. This is the only way (perhaps there are better ones) I've ever been successful in creating HTML scrapers in PHP.

Categories