Give me one good reason to do this
if( isset($_GET['key']) && ($_GET['key'] === '123') )
{...
instead of this
if( #$_GET['key'] === '123' )
{...
I'm asking for this very specific code case, and not in general!
Following reasons are not welcome:
"using # will slow down the application by some nanoseconds because the
error is created anyway (even if it's supressed)." Well I prefer slower
code but more readable.
"using # is bad habit." It might be true in general, but I don't belive in this case (moreover bad habits might
depend on the context, on PHP manual in function like fopen they
suggest to use # in certain circumstainces, see Errors/Exceptions
at http://www.php.net/manual/en/function.fopen.php)
The performance impact isn't actually the best argument against this example and you would have to measure the performance in your own application to decide whether this is a problem. It is more likely to cause a slow down if a large number of items being checked are not set or if you placed a check such as this within a loop.
The main problem associated with using the # operator is that it is likely to become a convention in your code, so while your example may seem innocuous, you may later find yourself or your team using:
if( #IsAvailable() ) {
And the error suppression starts to hide real errors that you didn't anticipate as well as those that you did - and you have no idea what happened as you get no exception information at all.
Think about how much you could be slowing your application down when your website / app starts getting tens / hundreds of thousands (or more) of requests a day. If you're suppressing errors as a standard, you probably have dozens for every request - suddenly, you're site is noticeably slower than you would want it to be.
In addition to this, you could end up suppressing errors that you actually want to be aware of while developing.
If you don't take performance issue as argument, then it is indeed OK. But it does not has to be in all cases, because # will supress all possible errors, even those, you did not think about. But in this case, it seems there are not possible other errors that the one you want to supress.
I agree with you that preceed isset() before reading value is very ugly and I don't like to write it either. But insert # before statement seems ugly to mee to. It can decrease readibility in longer code.
Good news is, that since PHP 7 we can use much nicer way, null-coalescence operator ?? which works like this:
if($_GET['key'] ?? '' === '123' ) {}
It is basically replacement for this:
$result = isset($value) ? $value : $anotherValue;
now you can use
$result = $value ?? $anotherValue;
Related
When I learned PHP I was taught to make my code error free, but to still hide errors in production code to ensure a clean user experience.
I've recently been involved in some projects where the original writer took the approach of leaving in errors and warnings and even utilizing them to achieve something, rather than write code without it.
For example, the code would look like this:
$numm = 0;
while($numm < 10){
$var = "something,".$var;
$numm++;
}
This code will throw a non-fatal Noticethe first time through the loop, because $var doesn't exist for the first concatenation.
There are tons of other examples where they either ignore errors, or even utilize them (to end loops, etc.) but then hide them from the user.
To me, this seems like bad practice, but I could just be OCD.
A Notice is a bug waiting to happen. I routinely run development with error_reporting(E_ALL); set. I want to find the bugs before they are a problem, and not simply ignore the problems, potential, or not.
Set a requirement of isset($var) in the while loop.
One thing that I have always found annoying was doing things like:
$var = isset($var) ? "something,".$var : "something,";
This one liner will prevent the error but not ideal way of doing it when you consider the number of possible uses. Imagine an associative array that returns that doesn't always have all it's key/values you would expect set.
One approach that i take to nearly all my apps is creating and using the following function:
function rtnVal(&$val, $default = null){
return isset($val) ? $val : $default;
}
so in this case, all I have to do is this:
$var = "something,".rtnVal($var);
Easy ain't it? In case you didn't know, defining
function rtnVal(&$var) { ... }
instead of:
function rtnVal($var) { ... }
(notice the & symbol) means that $var is a 'placeholder' (passed by reference) and not actually passed. So when you use it, it doesn't have to be previously set.
There is one limitation to this though and that's working with Objects, they don't like being passed by reference this way so for those, I have yet to find a better 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 #?).
The following code generates a notice if $n is not set. Solving it requires an additional statement (isset($n)) or to "declare" the $n ($n=''). But what consequences does this notice have? The below code is a lot neater and lets say we turn error_reporing off in production no difference is visible frontend. Does something bad follows? Prestanda, readability etc? (sorry for the bad english)
if($n==1){
//do something
}
There is no "consequence" to notices, per sé, other than bad coding practices. You should be coding with error_reporting set to E_ALL on your development machines, so obviously the consequence there is a lot of notices...
I would argue that your code actually isn't neat, because you're testing a variable which doesn't get set previously.
A suggestion would be something like this:
<?php
if (!empty($n) && $n == 1)
{
//do something
}
empty checks for existence automatically (just like calling isset before it) but it also checks to make sure your value doesn't evaluate as false with values like false, 0, or '' (empty string).
A notice means that while your code will work as expected, it isn't written "like it should be". It's like the compiler telling you "I know what you mean here and I can do it, but you shouldn't rely on this. Please write it differently so I don't have to make assumptions".
Therefore a notice by itself doesn't mean that something bad happens most of the time. However, I wouldn't call anyone who accepts notices in their code a professional programmer because fixing the notices is a pretty simple task and not having any notices says that you understand the language's basics well. If someone can't or don't want to do even this much, it says something about them.
In your specific example, something like this should be done:
$n = null; // or some other appropriate initial value
// possibly change the value of $n here
if($n==1) {
//do something
}
Note that by writing the extra $n = null, you are not making the program any different as far as the compiler is concerned (it will end up doing that itself at the same time it gives out the notice anyway). But you are making it very different as far as someone reading the code is concerned: with this code they won't have a "WTF did this $n come from???" moment.
Normally in the production environments all error reporting which come strait from PHP libraries is turned off or parsed before showing to end user (it`s still logged).
There are no consequences in notice, it`s just notice to developer that something bad could happen in this place, in your example initializing the variable with value.
I encountered one function that handling "PHP Notice" can be beneficial.
The function is:
geoip_record_by_name()
This function return "false" and send "PHP Notice" on IP's that do not find in its database.
The standard is that IP's reserved for internal networks, or Localhost will not be found.
As a horrible practice this function treat this normal condition as bed coding. WRRRRR!!!
There is solution to filter local IP,s before sending to this function ( assuming that all other addresses are covered by geoip database).
I consider this geoip_record_by_name() as pest function that handling of "PHP Notice" is justified.
Discussion related to this pest function
Is it OK to use # when extracting a possibly missing value from a PHP array? Example:
$value = #$array['possibly_missing_key'];
The intended behavior:
if (isset($array['possibly_missing_key'])) {
$value = $array['possibly_missing_key'];
} else {
$value = null;
}
I want to know, before spreading the usage pattern.
The # operator suppresses error messages, and using it potentially sets up your code for other errors and unexpected behavior that end up hard to track down. Thus it's most certainly an antipattern.
Thus, I would very much prefer the second bit. It makes it much clearer
that it may not be present in the array, and
what the default value is if it's not present
To make it more concise you can use the ternary conditional operator ?:, as seen in Mark Baker's answer. Slightly less code and more symbols but the meaning is well-recognized.
Actually the isset variation is the anti-pattern. If you just use isset($var)?$var:NULL with the intention to suppress the "error", then you've achieved nothing over using the proper syntax for suppressing errors. It has the same outcome, yet is less readable.
People are arguing for that because of perceived "cleanliness" and because using isset is a micro optimization. Avoiding # and using isset as syntactic salt replacement is just cargo cult programming.
Or
$value = (isset($array['possibly_missing_key'])) ? $array['possibly_missing_key']: null;
Ignoring warnings is definitely an antipattern; so yes, it's an anti-pattern (and I can guarantee that if you learn to suppress warnings, one of them will come back and bite you in the posterior, if not worse).
Also, while the second version is more verbose, it gives the uninitialized variable a known state (or can be used to handle the problem, if the variable is supposed to be filled).
The third option:
$value = (isset($array['key']) ? $array['key'] : null);
I know this doesn't directly answer the question; I would have put it as a comment, except it really needed to be formatted.
The idea here is that if you're trying to make your code shorter by using a one-liner instead of an if-else block, then you can still get it into a succinct one-liner using a ternary operator, giving you the best of both worlds.
The second block of code (or Mark Baker's alternative which will work exactly the same) is better. I'm not entirely sure about PHP, but in many other programming languages, to simply ignore a variable would almost definitely throw an error. At least with the second block you are initializing the variable to some value or memory location.
Error suppression should be more commonly used if you expect a function to throw an expected error in the end-product (however, much of the time this will not be the case).
Good luck!
Dennis M.
I am a C++ programmer starting with PHP. I find that I lose most of the debugging time (and my selfesteem!) due to undefined variables. From what I know, the only way to deal with them is to watch the output at execution time.
Are other strategies to notice these faults earlier (something like with C++ that a single compile gives you all the clues you need)?
This is a common complaint with PHP. Here are some ideas:
Use a code analysis tool. Many IDEs such as NetBeans will help also.
Just run the code. PHP doesn't have an expensive compilation step like C++ does.
Use unit testing. Common side effects include: better code.
Set error_reporting(-1), or the equivalent in your ini file.
Get xdebug. It's not preventative, but stack traces help with squishing bugs.
isset(), === null (identity operator), and guard clauses are your friends.
Loose and dynamic typing are a feature of the language. Just because PHP isn't strict about typing doesn't mean you can't be. If it really bugs you and you have a choice, you could try Python instead—it's a bit stricter with typing.
Log your E_NOTICE messages to a text file. You can then process logs with automated scripts to indicate files and lines where these are raised.
No. In PHP, you can only know a variable doesn't exist when you try to access it.
Consider:
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
var_dump($line);
You have to restructure your code so that all the code paths leads to the variable defined, e.g.:
$line = "default value";
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
var_dump($line);
If there isn't any default value that makes sense, this is still better than isset because you'll warned if you have a typo in the variable name in the final if:
$line = null;
if ($data = file('my_file.txt')) {
if (count($data) >= 0)
$line = reset($data);
}
if ($line !== null) { /* ... */ }
Of course, you can use isset1 to check, at a given point, if a variable exists. However, if your code relies on that, it's probably poorly structured. My point is that, contrary to e.g. C/Java, you cannot, at compile time, determine if an access to a variable is valid. This is made worse by the nonexistence of block scope in PHP.
1 Strictly speaking, isset won't tell you whether a variable is set, it tell if it's set and is not null. Otherwise, you'll need get_defined_vars.
From what I know the only way to deal with them is to watch the output at execution time.
Not really: To prevent these notices from popping up, you just need to make sure you initialize variables before accessing them the first time. We (sadly IMO) don't have variable declaration in PHP, but initializing them in the beginning of your code block is just as well:
$my_var = value;
Using phpDocumentor syntax, you can also kind of declare them to be of a certain a type, at least in a way that many IDEs are able to do code lookup with:
/** #desc optional description of what the variable does
#var int */
$my_var = 0;
Also, you can (and sometimes need to) use isset() / empty() / array_key_exists() conditions before trying to access a variable.
I agree this sucks big time sometimes, but it's necessary. There should be no notices in finished production code - they eat up performance even if displaying them is turned off, plus they are very useful to find out typos one may have made when using a variable. (But you already know that.)
Just watch not to do operations that requires the variable value when using it the first time, like the concatenate operator, .=.
If you are a C++ programmer you must be used to declare all variables. Do something similar to this in PHP by zeroing variables or creating empty array if you want to use them.
Pay attention to user input, and be sure you have registered globals off and check inputs from $_GET and $_POST by isset().
You can also try to code classes against structural code, and have every variable created at the beginning of a class declaration with the correct privacy policy.
You can also separate the application logic from the view, by preparing all variables that have to be outputted first, and when it goes to display it, you will be know which variables you prepared.
During development stages use
error_reporting(E_ALL);
which will show every error that has caused, all NOTICE errors, etc.
Keep an eye on your error_log as well. That will show you errors.
Use an error reporting system, example:
http://php.net/manual/en/function.set-error-handler.php
class ErrorReporter
{
public function catch($errno, $errstr, $errfile, $errline)
{
if($errno == E_USER_NOTICE && !defined('DEBUG'))
{
// Catch all output buffer and clear states, redirect or include error page.
}
}
}
set_error_handler(array(new ErrorReporter,'catch'));
A few other tips is always use isset for variables that you may / may not have set because of a if statement let’s say.
Always use if(isset($_POST['key'])) or even better just use if(!empty($_POST['key'])) as this checks if the key exists and if the value is not empty.
Make sure you know your comparison operators as well. Languages like C# use == to check a Boolean state whereas in PHP to check data-types you have to use === and use == to check value states, and single = to assign a value!
Unless I'm missing something, then why is no one suggesting to structure your page properly? I've never really had an ongoing problem with undefined variable errors.
An idea on structuring your page
Define all your variables at the top, assign default values if necessary, and then use those variables from there. That's how I write web pages and I never run into undefined variable problems.
Don't get in the habit of defining variables only when you need them. This quickly creates spaghetti code and can be very difficult to manage.
No one likes spaghetti code
If you show us some of your code we might be able to offer suggestions on how you can better structure it to resolve these sorts of errors. You might be getting confused coming from a C background; the flow may work differently to web pages.
Good practice is to define all variable before use, i.e., set a default value:
$variable = default_value;
This will solve most problems. As suggested before, use Xdebug or built-in debugging tools in editors like NetBeans.
If you want to hide the error of an undefined variable, then use #. Example: #$var
I believe that various of the Code Coverage tools that are available for PHP will highlight this.
Personally, I try and set variables, even if it's with an empty string, array, Boolean, etc. Then I use a function such as isset() before using them. For example:
$page_found = false;
if ($page_found==false) {
// Do page not found stuff here
}
if (isset($_POST['field'])) {
$value = $_POST['field'];
$sql = "UPDATE table SET field = '$value'";
}
And so on. And before some smart-ass says it: I know that query's unsafe. It was just an example of using isset().
I really didn't find a direct answer already here. The actual solution I found to this problem is to use PHP Code Sniffer along with this awesome extension called PHP Code Sniffer Variable Analysis.
Also the regular PHP linter (php -l) is available inside PHP Code Sniffer, so I'm thinking about customizing my configuration for regular PHP linting, detecting unused/uninitialized variables and validating my own code style, all in one step.
My very minimal PHPCS configuration:
<?xml version="1.0"?>
<ruleset name="MyConfig">
<description>Minimal PHP Syntax check</description>
<rule ref="Generic.PHP.Syntax" />
<rule ref="VariableAnalysis" />
</ruleset>