PHP: #! vs !# -- whats the diff? - php

I am working on file_get_contents func (I know notices on network issue's and Returns FALSE indicating operation failure). For now I don't care about the network errors and I just i want the network res and keep trying until i get it.
So, i put # before the the func to stop notices from making my cli window full of unwanted texts.
And To make the thing work in a loop i added !
while (($data=!#file_get_contents('http://example.com/')) === false);
But What diff does it make from this,
while (($data=#!file_get_contents('http://example.com/')) === false);
So, My question is whats the difference between them??

Quick answer: they're functionally identical
# is the PHP error suppression operator, which results in hiding all errors from the subsequent expression.
When you say
!#function()
, you're saying to suppress all errors that might arise from function() (and any deeper function calls, etc), and then negating the result.
With
#!function()
the whole of !function() is treated as the expression, and so any errors from the function are again hidden.
See https://3v4l.org/dPINA for an example - notice how the warning is suppressed in both cases.

#!file_get_contents = The ! evaluates the result of the function as a boolean (true or false). The # suppresses all warnings from the result of the expression.
!#file_get_contents = The # suppresses all warnings from the function, then the ! evaluates the result of the error-suppressed function as a boolean (true or false).
Edit: My answer was marked as accepted, so I edited with the correct behavior from iainn's answer.

Related

Why is yaml_parse_file returning true?

For some reason when I run the .php script:
$s = yaml_parse_file("../config.yaml") || die("YAML file not found");
var_dump($s);
it returns:
bool(true)
What on earth is going on? This has happened out of nowhere it was working fine for a week and I can't seem to fix it. I have installed using pecl install yaml and added "extension=yaml.so" to php.ini?
I have used online yaml regex testers and they return that it is okay. The format is (obviously with content):
title:
email: hello#
logo: images/logo.png
download-file: .dmg
recaptcha:
pub:
priv:
meta:
keywords: mac, osx
description:
ico: images/icon.ico
You're assigning the result of the boolean operation to $s, since the || operator has a higher precedence than the assignment. So it's being evaluated as follows:
$s = (yaml_parse_file("../config.yaml") || die("YAML file not found"));
This returns true, since the initial expression returns a "truthy" value.
If you wrap the assignment in brackets, it will work as you are expecting:
($s = yaml_parse_file("../config.yaml")) || die("YAML file not found");
...
See https://eval.in/960405
The code worked before, when it used to read:
$s = yaml_parse_file("../config.yaml") or die("YAML file not found");
You recently changed or with || (why?) without knowing that they are different operators and they have different precedence.
or has the lowest precedence and the expression above is evaluated as:
($s = yaml_parse_file(...)) or die(...)
|| has higher precedence than the assignment (=) and the expression posted in the question evaluates as:
$s = (yaml_parse_file(...) || die(...))
To solve the issue, first you should forget about or die(). It is bad coding practice spread out by PHP tutorial more than 15 years ago. It's sad that many of them are still available on the web and teach the newbies how to throw a white page on the face of their visitors when an error happens.
or die() is useless. If yaml_parse_file() (or whatever function call you "handle" using it) returns FALSE, the next statement that attempts to use the result most probably will fail anyway. And you'll get a more or less descriptive error message in php_errors.log. That error message help you debug the code and identify and fix the errors. or die doesn't help with anything. It just hides the error under the carpet and tells the visitor what they can see by themselves: that your site doesn't work. But it doesn't tell you what was the error or how to fix it.

is elvis operator with error handling safe for set default value?

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.

I cant figure out the diffrence between following two syntaxes

while($rowForStateList = #mysql_fetch_array($resForStateList))
{
$sid[$i] = $rowForStateList['state_auto_id'];
$sname[$i] = $rowForStateList['state_name'];
$spid[$i] = $rowForStateList['country_auto_id'];
$i++;
}
AND
while($rowForStateList = mysql_fetch_array($resForStateList))
{
$sid[$i] = $rowForStateList['state_auto_id'];
$sname[$i] = $rowForStateList['state_name'];
$spid[$i] = $rowForStateList['country_auto_id'];
$i++;
}
The difference is that #mysql_fetch_array in first code sample fetches the array suppressing any errors, while mysql_fetch_array do the same but not suppressing errors. Actually, the second one is more correct way.
The evil of using # is in that it comlicates debugging a lot. With this suppression, in case of error you'll end up with empty arrays, so it will look just like query used to get $resForStateList have returned empty result. But, you actually might have broken query, refused database connection and whatever else. And with # you will never know that something goes wrong.
So, don't use #. Instead, use error handling functions. And the best way is to check if something could cause error, e.g. mysql_query returns false in case of any error, so you might want to check it like
$result = nysql_query("qwerty");
if (!$result){
echo mysql_error();
}
The difference is that the former will mask any errors that occur in mysql_fetch_array(), making debugging more difficult.
The # in the first version basically means "If this function triggers an error, just hide it, don't log or display it".
Don't ever use the # error suppression operator! Not only does it make for a debugging nightmare, but it also harms application performance. Use error_reporting, log_errors and display_errors to set proper error message behaviour instead.
Don't use the # operator in this case. mysql_fetch_array will only throw an error if the resource is not valid. You should have checked this before, after you got this resource.
The difference is the error reporting.
If you set a # before mysql_fetch_array, any errors will be ignored.
see php errorcontrol
the only difference is that the # in front of the mysql_fetch_array in the first code will supress any error from being displayed on the screen.
the first one suppresses errors: http://davidwalsh.name/suppress-php-errors-warnings
They are identical. The first mysql_fetch_array() will not produce error messages due to the suppression operator #.
The first one will silently ignore any error. The second one will display any error or exceptions thrown the mysql_fetch_array (for example, connection problem). The magic comes from the # sign.
#mysql_fetch_array($resForStateList))
doesn't show up any message in case of an error.
That's all.
The # is an operator thet suppresses errors. Your statement will not throw errors when the # is added. You can read more here: http://thesmithfam.org/blog/2006/05/07/php-the-operator/
When you prepend '#' to an expression, any error messages that might be generated will be ignored (ie. no error output will be generated). Anyway if the track_errors feature is enabled, any error message generated by the expression will be saved (and overwritten on each error) in the variable $php_errormsg.
Check PHP Error Control for more details.
Actually, I prefer to use expression widthout '#' and handle all exceptions with a function that log all message in a file with error_log(). Something like:
function error_handler($errno, $errstr, $errfile=null, $errline=null, $errcontext=null) {
error_log($errstr, 3, 'debug.log');
}
set_error_handler('error_handler', ERROR_REPORTING);

In php using # instead of isset

In some conditions, may I use an # character instead of using the longer isset() function?
If not, why not?
I like to use this because in a lot cases I can save several quotation marks, brackets and dots.
I assume you're talking about the error suppression operator when you say # character, but that isn't a replacement for isset().
isset() is used to determine whether or not a given variable already exists within a program, to determine if it's safe to use that variable.
What I suspect you're doing is trying to use the variable regardless of its existance, but supressing any errors that may come from that. Using the # operator at the beginning of a line tells PHP to ignore any errors and not to report it.
The # operator is shorthand for "temporarily set error_reporting(0) for this expression". isset() is a completely different construct.
You shouldn't just use an #. The # suppresses warnings. It doesn't mean the code is correct, and warnings might still get added to your log file depending on your settings. It is much better to use isset to do the check.
As far as I know # is no substitution for isset(). Its an error suppression operator which prevents displaying errors in case they do exist in the script. Its also a pretty bad habit if used in PHP code.
It technically works, but there are a few reasons why I prefer the explicit isset solution when creating output, which I assume is what you're doing:
If I'm a new developer working on your old code, I recognize the isset idiom. I know what you're trying to do. With #, it's not so easy to figure out your intention.
Suppose you want to check if an object's property is set, like $user->name. If you just use error suppression to see if name is set, you will never be notified if $user is undefined. Instead, it's better to run isset($user->name) and be explicit, so that, if $user is undefined, you will be notified of the error.
Error suppression is a bad habit overall. Error notices are good, and you should make it as easy as possible to be notified of errors. Suppressing them when it's not necessary leads to problems in the future.
It depends on what you are trying to do. For instance, if you are performing a var_dump() or other debugging and know that sometimes your value will not be set I'd say in this situation it is ok.
var_dump(#$_REQUEST['sometimesIamSet']);
If you are using it in this case:
if(#$_REQUEST['something']){
// do something
}
else{
// do something else
}
I would strongly advise against it. You should write your code to do explicitly what you want to do.
if(isset($_REQUEST['something'])){
// Hurray I know exactly what is going on!
}
else{
// Not set!
}
The only instance in production I can think about using # is when you want to throw your own error. For example
$database_connection = #db_connect_function();
if($database_connection === false){
throw new Exception("DB connection could not be made");
}
Also, look at PaulPRO's answer. If what he is saying is indeed true, your log files could also be logging warnings that you don't know about. This would result in your log files being less helpful during debugging after release.
If for no other reason, don't use # as a substitute for isset because of this:
Look at this code:
echo (#$test) ?: 'default';
If $test is 'something' then you'll get 'something'.
If $test is empty, null or doesn't exist, then you'll get 'default';
Now here's where the problem comes in:
Suppose '0' or FALSE are valid answers?
If $test is '0' or FALSE then you'll get 'default' NOT '0' as you would want.
The long-format ternary is what you should use:
echo (isset($test)) ? $test : 'default';
Not much more coding, and more reliable when it comes to dealing with arguments that can evaluate as boolean false.
the # operator also makes your code run slower, as pointed out here:
http://php.net/manual/en/language.operators.errorcontrol.php
But as it's been pointed out, the code only runs measurably slower if an error occurs. In that case, code using isset instead of # operator is much faster, as explained here:
http://seanmonstar.com/post/909029460/php-error-suppression-performance

Why does #unset give a parse error?

Why can't you hide errors with the # operator when calling unset? The following results in a parse error:
#unset($myvar);
The # operator only works on expressions, and unset is a language construct, not a function. See the manual page for more information:
Note: The #-operator works only on
expressions. A simple rule of thumb
is: if you can take the value of
something, you can prepend the #
operator to it. For instance, you can
prepend it to variables, function and
include() calls, constants, and so
forth. You cannot prepend it to
function or class definitions, or
conditional structures such as if and
foreach, and so forth.
You can hide errors by prefixing # to functions/statements. However unset is a language construct, therefore it doesn't support the #-rule.
The good thing is that unset() never fails even if the variable didn't exist to begin with, so this shouldn't be necessary.
As nightcracker mentionned though, using # is pretty bad practice.
The error suppression operator only works on expressions:
unset is a language construct and not a function, so # cannot be used.
Why can't you hide errors with the # operator when calling unset?
I do not know. But you should not be using the error suppression operator (#) anyway. There are two distinct scenarios:
Developemnt
You want to see all errors right at the moment they happen, preferably with the raw error message that PHP gives you.
Production
You want to let no PHP error message bubble to the user. Instead you want to log the PHP error message and display your own message that a layman can understand.
You cannot achieve this distinction when you use #. You should separate theses scenarios by configuring display_errors, error_reporting and setting an error handler with set_error_handler.

Categories