I am currently refactoring some code for work and I have come across some function calls prefixed by the "#" symbol. As I understand it, this is intended to escape PHP error reporting if the call fails.
Is this type of thing good practice? I understand the rationale in a development environment but when the site is pushed to production shouldn't all errors be handled properly rather than just escaped?
The use of this symbol would therefore mean that the developer has to sort through the code at a later stage to remove all error reporting escapes.
I am unsure whether to remove these symbols and just find a better way to handle potential errors or not.
For clarity, the function this was used on was the native PHP fsockopen() function.
That's probably among the worst practices you can come across in php code. It basically tells the interpreter to suppress errors and just try to do whatever the code asks it to do regardless of the outcome.
A great way to drag yourself and fellow teammates into all-nighter phantom bug hunts once the app has grown substantially.
Try-catch with custom exception handling is the way to go.
I think it is sometimes understandable to use # for calling functions like fsockopen(), because when they fail they will raise a warning as well as returning false.
There may be cases where you expect these calls to fail regularly and therefore do not want a warning to be raised. Obviously you shouldn't be displaying warnings in production and should be logging them instead, but you might still want to use the # operator to stop your logs getting full. You could stop warnings getting reported at all by changing the error_reporting setting but that is not ideal.
That's called the error control operator, and is generally a very scary thing to consider using. A warning from the manual (the emboldening is mine):
Currently the "#" error-control
operator prefix will even disable
error reporting for critical errors
that will terminate script execution.
Among other things, this means that if
you use "#" to suppress errors from a
certain function and either it isn't
available or has been mistyped, the
script will die right there with no
indication as to why.
Using the "#" operator is very useful when you know that the function call can fail, like, for example, the fsockopen call. Best practice is to use this only when the function you are calling often fails and is a valid case in your application. Also, you should definitely check the return value of the function after calling it:
$fp = #fsockopen($hostname, $port);
if ($fp === false) {
// handle connection failure
}
else {
// handle connection success
}
You should avoid two things:
Not checking the return value;
Using the "#" operator where you don't expect an error -- for example when opening a local file or sending headers. When opening a local file fails, that is an error and it should be handled properly.
Note: you might also want to look at set_error_handler()
if you use your custom error-handlers, the # operator will not help you,
you will always get error-events from situations where your are handling the "Warning" in your code ... like at fsockopen etc.
so you can simple suppress effectively the warning this way:
function renameWithOutExpectedAndSelfHandledErrors( ... ) {
set_error_handler(function(){}); // deactivate all errors
$result = rename('not existing','blafussel');
restore_error_handler(); // restore old error-situation
return $result;
}
Related
in my code is usually use if(!isset()) for set default value if the variable is empty
ex :
if(isset($_POST['noreg']))
{
$noreg = $_POST['noreg'];
}
else
{
$noreg = 'empty';
}
my friend suggest me to use elvis operator with error handling, and it looks shorten than before,
$noreg = #$_POST['noreg'] ?: 'empty';
it works fine like my old code
but is it safe or it has any risk if i use it?
can anyone help me for this?
thanks
The # operator suppresses error reporting. That means there's still an error being produced, but it's being silenced. That's problematic for three reasons:
It's probably slower to raise and then discard an error than an isset check would be.
If you have a custom error handler, that handler may ignore # and still produce an error.
You have no idea what other kinds of errors you may be suppressing that you're not expecting.
Particularly, what if you accidentally write #$_PSOT['noreg']? PHP's error reporting won't be alerting you to this mistake and you're in the dark. If you'd use filter_input(INPUT_POST, 'noreg') or array_key_exists('noreg', $_POST), such mistakes could not be made.
(This example may be a bit contrived since isset() will suppress the same error, but it's to illustrate the pitfalls of using error suppression and why one must be very conscious of it.)
If you use it for simple variable initialization then it's ok. It will work on any expression & when preceding it, it will suppress the error.
Straight from documentation http://php.net/manual/en/language.operators.errorcontrol.php
PHP supports one error control operator: the at sign (#). When
prepended to an expression in PHP, any error messages that might be
generated by that expression will be ignored.
If you have set a custom error handler function with
set_error_handler() then it will still get called, but this custom
error handler can (and should) call error_reporting() which will
return 0 when the call that triggered the error was preceded by an #.
Currently the "#" error-control operator prefix will even disable
error reporting for critical errors that will terminate script
execution. Among other things, this means that if you use "#" to
suppress errors from a certain function and either it isn't available
or has been mistyped, the script will die right there with no
indication as to why.
The at sign is used to hide error messages. As far as I see, there is absolutely no use case or excuse for using it.
You can hide errors in production by changing php ini settings while still outputting errors to log files
#-sign makes it difficult for fellow programmers to identify where the problem is
Error messages are your friends when you are developing. Find errors fast and fix them
A friend of mine just spent a couple of hours trying to find out why the software works on one system and not on another. This would have taken about 10 seconds if the library developer wouldn't have used #-sign.
Am I close-minded when I say that there is absolutely no value to #-sign, is there a valid case?
There is some value to the # sign, but it's normally a code smell.
Consider the following: you're developing a library that needs to be compatible with multiple projects, and you don't want to change the error handler globally. Unfortunately, many PHP functions (including the sockets and streams related ones) throw a PHP error rather than an exception on failure. The "#" sign is then useful for hiding the error if and only if the error is then checked for manually and an exception is thrown if it occurred.
It's also useful for filesystem operations.
Mainly you're right though...it's normally terrible practice (:
There are a few rare situations where it indeed makes sense to use error suppression.
One of them are atomic filesystem operations. E.g. instead of writing
if (file_exists($fileName)) {
unlink($fileName);
}
you just do
#unlink($fileName);
This makes sure that your code is not subject to race conditions.
Generally # is useful in situations where PHP chose an inappropriate error model for a function. The above unlink function is one such example. Similarly there are other functions where PHP throws errors, even though it shouldn't (instead using return values or catchable exceptions).
In most cases you should indeed not use it. Some cases it makes sense though:
unlink()
while (#ob_end_flush());
There might be some other edge cases, but besides these you should really never ever supress errors.
As with all tools available (both in programming and outside of it), everything has a legitimate use case.
The first example that comes to mind for the error suppression operator would be something like
if (!#unlink($file)) {
// I am already handling the error. I don't care what caused it.
// Even NOT handling this case at all could be a legitimate reaction
// depending on circumstances.
}
When using DOMDocument, invalid HTML will throw warnings, we don't care on most cases.
When using PEAR's Mail, you'll get warnings about functions that shouldn't be called statically, that's because Mail supports PHP 4. These can be safely ignored.
When using unlink(), you suppress errors to prevent race conditions.
The most common place I have seen it used is for suppressing mysql errors when working with a db. Then the user checks the response instead and prints an appropriate error message.
Example
<?php
$link = #mysql_connect('localhost', 'mysql_user', 'mysql_password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
echo 'Connected successfully';
mysql_close($link);
?>
I have also seen it used when working with ftps and sftps.
But I agree with you that I find its uses limited. If one ends up in a situation where one feels the need to use the #-sign at own produced code, I think it's time to rethink the solution.
So I'm working on cleanup of a horrible codebase, and I'm slowly moving to full error reporting.
It's an arduous process, with hundreds of notices along the lines of:
Notice: Undefined index: incoming in /path/to/code/somescript.php on line 18
due to uses of variables assuming undefined variables will just process as false, like:
if($_SESSION['incoming']){
// do something
}
The goal is to be able to know when a incorrectly undefined variable introduced, the ability to use strict error/notice checking, as the first stage in a refactoring process that -will- eventually include rewriting of the spots of code that rely on standard input arrays in this way. There are two ways that I know of to replace a variable that may or may not be defined
in a way that suppresses notices if it isn't yet defined.
It is rather clean to just replace instances of a variable like $_REQUEST['incoming'] that are only looking for truthy values with
#$_REQUEST['incoming'].
It is quite dirty to replace instances of a variable like $_REQUEST['incoming'] with the "standard" test, which is
(isset($_REQUEST['incoming'])? $_REQUEST['incoming'] : null)
And you're adding a ternary/inline if, which is problematic because you can actually nest parens differently in complex code and totaly change the behavior.
So.... ...is there any unacceptable aspect to use of the # error suppression symbol compared to using (isset($something)? $something : null) ?
Edit: To be as clear as possible, I'm not comparing "rewriting the code to be good" to "#", that's a stage later in this process due to the added complexity of real refactoring. I'm only comparing the two ways (there may be others) that I know of to replace $undefined_variable with a non-notice-throwing version, for now.
Another option, which seems to work well with lame code that uses "superglobals" all over the place, is to wrap the globals in dedicated array objects, with more or less sensible [] behaviour:
class _myArray implements ArrayAccess, Countable, IteratorAggregate
{
function __construct($a) {
$this->a = $a;
}
// do your SPL homework here: offsetExists, offsetSet etc
function offsetGet($k) {
return isset($this->a[$k]) ? $this->a[$k] : null;
// and maybe log it or whatever
}
}
and then
$_REQUEST = new _myArray($_REQUEST);
This way you get back control over "$REQUEST" and friends, and can watch how the rest of code uses them.
You need to decide on your own if you rate the # usage acceptable or not. This is hard to rate from a third party, as one needs to know the code for that.
However, it already looks like that you don't want any error suppression to have the code more accessible for you as the programmer who needs to work with it.
You can create a specification of it in the re-factoring of the code-base you're referring to and then apply it to the code-base.
It's your decision, use the language as a tool.
You can disable the error suppression operator as well by using an own callback function for errors and warnings or by using the scream extension or via xdebug's xdebug.scream setting.
You answered you question yourself. It suppress error, does not debug it.
In my opinion you should be using the isset() method to check your variables properly.
Suppressing the error does not make it go away, it just stops it from being displayed because it essentially says "set error_reporting(0) for this line", and if I remember correctly it would be slower than checking isset() too.
And if you don't like the ternary operator then you should use the full if else statement.
It might make your code longer but it is more readable.
I would never suppress errors on a development server, but I would naturally suppress errors on a live server. If you're developing on a live server, well, you shouldn't. That means to me that the # symbol is always unacceptable. There is no reason to suppress an error in development. You should see all errors including notices.
# also slows things down a bit, but I'm not sure if isset() is faster or slower.
If it is a pain to you to write isset() so many times, I'd just write a function like
function request($arg, $default = null) {
return isset($_REQUEST[$arg]) ? trim($_REQUEST[$arg]) : $default;
}
And just use request('var') instead.
Most so-called "PHP programmers" do not understand the whole idea of assigning variables at all.
Just because of lack of any programming education or background.
Well, it isn't going a big deal with usual php script, coded with considerable efforts and consists of some HTML/Mysql spaghetti and very few variables.
Another matter is somewhat bigger code, when writing going to be relatively easy but debugging turns up a nightmare. And you are learn to value EVERY bloody error message as you come to understanding that error messages are your FRIENDS, not some irritating and disturbing things, which better to be gagged off.
So, upon this understanding you're learn to leave no intentional errors in your code.
And define all your variables as well.
And thus make error messages your friends, telling you that something gone wrong, lelping to hunt down some hard-spotting error which caused by uninitialized variable.
Another funny consequence of lack of education is that 9 out of 10 "PHP programmers" cannot distinguish error suppression from turning displaying errors off and use former in place of latter.
I've actually discovered another caveat of the # beyond the ones mentioned here that I'll have to consider, which is that when dealing with functions, or object method calls, the # could prevent an error even through the error kills the script, as per here:
http://us3.php.net/manual/en/language.operators.errorcontrol.php
Which is a pretty powerful argument of a thing to avoid in the rare situation where an attempt to suppress a variable notice suppressed a function undefined error instead (and perhaps that potential to spill over into more serious errors is another unvoiced reason that people dislike #?).
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Reference - What does this symbol mean in PHP?
I'm making a web application that uses URL queries to access different parts of the application. I was looking for a solution to make an invalid query like index.php?page=dashboarrrd display an error 404 message instead of a PHP error.
After some searching, I found that I could use something like the following to do the job:
if(!#include($fileName)){
#include("pageData/404.php");
}
And that makes sense, but I don't know why that works. I mean, what the heck does the # before the include mean? I totally understand include $filename; but I need an explanation for #include ($fileName)
the code you really need is
$fileName = "pagedata/".basename($_GET['page']).".php";
if(is_readable($fileName)) {
include($fileName);
} else {
include("pagedata/404.php");
}
and # has absolutely nothing to do here
# is one of biggest delusions coming from lack of experience.
Ones who using it do expect only one kind of error, while in fact there can be many more. And to gag ALL possible messages to suppress only one of them is definitely like to throw out the child along with the bath.
There is a fundamental problem that makes such misunderstanding so widespread:
Most PHP users cannot distinguish three sides of error control:
error handling
error reporting
user notification.
Most of time in sake of [3] people mess with (1) and (2). While each of them require separate treatment:
your program should raise no intentional errors. No error should be part of program logic. All errors that ever raised should be only unexpected ones.
if you expect some error, you have to handle it. Not gag with #, but gracefully handle. is_readable() in my code exactly for that.
error reporting is for the programmer and should be always at max. So, error logging should be enabled on a live site and a programmer have to check all errors occurred. And of course he would be interested in such errors, thus # will do only harm here.
User-level error messages should be different from system ones. Your 404.php is a good example of such user-friendly behavior. As for the system error messages, a user shouldn't be able to see them at all. Just turn display_errors off and see - there is no use for the # again!
This is the # Error Control Operator (quoting) :
When prepended to an expression in
PHP, any error messages that might be
generated by that expression will be
ignored.
In normal conditions, if include cannot load the file you've passed as a parameter, it'll emit a warning.
Prepending the # operator to include will prevent that warning from being emited -- and, so, from being displayed / logged.
So, the following portion of code :
include 'does-not-exist.php';
Will get you the following warnings :
Warning: include(does-not-exist.php) [function.include]: failed to open stream: No such file or directory
Warning: include() [function.include]: Failed opening 'does-not-exist.php' for inclusion
While this line :
#include 'does-not-exist.php';
Will get you not warning.
And, as a sidenote, for information : Five reasons why the shut-op operator (#) should be avoided
The # suppresses errors. This is generally discouraged, as when developing you want to see errors.
Errors are easy to suppress when moving to a production environment with the display_errors setting to off. So yea, in most cases, there really is no need for the error to be suppressed.
EDIT
As an extra tidbit to "improve" that, what I used to do when dynamically including a file, is have an array which acts as a "white list" of valid requests. This does not "have" to be an array, just what I chose to do an example with.
$whiteList = array('filename1', 'index', 'home', 'about');
if (in_array($filename, $whiteList)) {
include($filename);
}else {
include('page/404.php');
}
This would do a few things, 1 make you not need the error suppressor. Two, it would make it a bit more securer, as without this, you would need to do a basename call to filter the text to prevent certain type of include injections etc. (Not knowing if you did this already, just extra information).
So yea, you may want analyze / look at other ways to achieve this and above is just one method :)
The use of "#" simply suppresses the error that would normally result from (in this instance) a missing file. Whilst generally its use is a very bad idea, there are some rare exceptions, such as the code snippet you provide above.
For more information, see the Error Control Operators section of the PHP manual.
Additionally, you might find the existing Reference - What does this symbol mean in PHP? question worthy of a quick scan.
The # in php suppresses all error output. For instance, if you had error reporting for warnings, an # in front of a function that generated a warning would not display the warning text.
include is an example of such a construct. If the included file is not found, it will display a warning saying so. The # is not necessary in the code at all, it is just there so that the user will not see warnings.
However, it is better to use apache (or php if you prefer) to change ini for displaying errors on the development site and not displaying them on the production site. That would make the # symbol useless.
A better question is why you need to do this 404 include. Why are you including a file for display? Why not have apache handle 404 redirects on its own? Why wouldn't the file exist in the first place?
# suppresses error messages. The parentheses are optional in include, but whoever wrote that snippet included them.
#include() is the opposite of require(). The first will silently ignore an (optional and missing) include script, while the second will throw an error and halt the script when the (critical) dependency is missing.
In this instance it is only senseful within the if(). The second should preferrably not have an error suppression, as it doesn't mask any seriously security-relevant error message.
Currently, PHP would trigger (and log if logging is enabled) E_NOTICE 'errors' when accessing undefined variables and array indexes. Is there a way to make it abort on these, so that I know I don't miss any. Frankly, IMO, far too often a script SHOULD abort on such condition anyway, as it will inevitably break something farther down the execution path. In all other cases there is the '#' operator, that's what it is for, right?
I know I can use a custom error handler and abort on any condition. In fact I do use one already, but I do have places where I trigger notices myself (granted, E_USER_NOTICE instead of PHP's own E_NOTICE), and I also always return false letting PHP's own internal handler do its job - logging and aborting on errors, continuing on everything else.
Then there are other cases where PHP produces E_NOTICE without me wanting to abort the script. Basically, there is no way for me to know if a particular E_NOTICE is a result of an unset variable or a totally harmless condition (which notices should be caused by anyway).
Has anyone a neat and non-hackish solution? Some recommended way of doing this?
Cheers.
I'm sure there is no native PHP way to do this.
Extending your already existent error handler to look into the error message (stristr($errmsg, "undefined variable") ...) and die() if necessary is the best (and only) way that comes to mind.
You can user PHP function set_error_handler() to register a custom function that will handles any PHP error. Specify E_NOTICE as the second parameter so that your custom function will only receive E_NOTICE error. Then in that function, simply do 'exit;' if the second parameter which is the error message starts with 'Undefined offset:'.
Rather than try to hack around PHP's error handling, I suggest you enforce some constraints on your script and check your variables with PHP's isset, empty and is_null functions.
I'm not sure what you want. You want to abort on notices, but not every notice? You want to distinguish between the several types of E_NOTICES and abort on some? The only way to do this is to check the message in the error handler and not abort if the message is about undefined variables – which you shouldn't use, by the way.