PHP suppress errors when checking existence + value of boolean? - php

I have a PHP script that uses an array of options: $opts[]
$opts can contain 0 or more key value pairs. All values are boolean.
When checking for existence of a key, and then that the value is true, I have been doing the following:
if(isset($opts['small']) && $opts['small']) $classes .= 'smallBtn';
This works, but I feel it is a bit long winded.
After having a think about it, I have come up with the following alternative:
if(#$opts['small']) $classes .= "smallBtn";
This is much smaller, but relies on the # error suppression.
My question is, which is the better way to do this?
First is long winded, but explicit in what it is doing.
Second is shorter, but may be seen as bad coding practice?
UPDATE:
The 3rd option, and in my opinion the best, is using empty:
if(!empty($opts['small'])) $classes .= 'smallBtn';
From the manual:
No warning is generated if the variable does not exist. That means empty() is essentially the concise equivalent to !isset($var) || $var == false.

Using # to suppress errors is usually a bad thing to do since it makes debugging really difficult. For example, say you make a typo in variable name (note the double dollar sign):
if(#$$opts['small']) $classes .= "smallBtn";
This will be constantly false without throwing any errors.
If you want to shorten your code, maybe just use a function, something like:
function optionIsTrue($opts, $key) {
return isset($opts[$key]) && $opts[$key] === true;
}
if (optionIsTrue($opts, "small")) {
$classes .= 'smallBtn';
}

Personally, I would prefer the first approach with respect to Clean Code guidelines and Code Readability.
I wouldn't suppress any errors whereever possible.

The proper way is to do the long-winded check so that the error never occurs. Suppressing the error fixes the symptom but does not fix the error. The following excerpt from your question is the correct answer:
if(isset($opts['small']) && $opts['small']) $classes .= 'smallBtn';
You're right-on with wanting to make code shorter and easier to read. But I've seen a lot of PHP code done by other experts and the only '#' error suppression I have ever seen in production code is one I put there myself as a quick fix. After being chastised by colleagues, I promptly put in the proper long-winded check so the error never occurred.

I have made a comment but you couldn't see the diference, here it goes:
Well, according to PEAR Coding Standards you should simply, first one is the better aproach but for the best pratice, and for best understand after looking at it, just try to read this one:
if(isset($opts['small'])
&& $opts['small']
) {
$classes .= 'smallBtn';
}
And as much as i know, you never should suppress errors

Related

Is it good practice to ignore non-fatal errors?

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.

PHP # instead of isset to test a $_GET value

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;

Is #$array['possibly_missing_key'] an anti-pattern?

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.

E_NOTICE ?== E_DEBUG, avoiding isset() and # with more sophisticated error_handler

Which better ways exist to avoid an abundance of isset() in the application logic, and retain the ability to see debug messages (E_NOTICE) when required?
Presumption first: E_NOTICE is not an error, it's a misnomer and should actually be E_DEBUG. However while this is true for unset variables (PHP is still a scripting language), some file system functions etc. throw them too. Hence it's desirable to develop with E_NOTICEs on.
Yet not all debug notices are useful, which is why it's a common (unfortunate) PHP idiom to introduce isset() and # throughout the application logic. There are certainly many valid use cases for isset/empty, yet overall it seems syntactic salt and can actually obstruct debugging.
That's why I currently use an error_reporting bookmarklet and a dumb on/off switch:
// javascript:(function(){document.cookie=(document.cookie.match(/error_reporting=1/)?'error_reporting=0':'error_reporting=1')})()
if (($_SERVER["REMOTE_ADDR"] == "127.0.0.1")
and $_COOKIE["error_reporting"])
{
error_reporting(E_ALL|E_STRICT);
}
else {/* less */}
However that still leaves me with the problem of having too many notices to search through once enabled. As workaround I could utilize the # error suppression operator. Unlike isset() it does not completely kill debugging options, because a custom error handler could still receive suppressed E_NOTICEs. So it might help to separate expected debug notices from potential issues.
Yet that's likewise unsatisfactory. Hence the question. Does anyone use or know of a more sophisticated PHP error handler. I'm imagining something that:
outputs unfiltered errors/warnings/notices (with CSS absolute positioning?)
and AJAX-whatnot to allow client-side inspection and suppression
but also saves away a filtering list of expected and "approved" notices or warnings.
Surely some framework must already have a user error handler like that.
Basically I'm interested in warning / notice management.
Full E_NOTICE supression is really not desired.
E_NOTICES are wanted. Just less of them. Per default highlight the ones I might care about, not the expected.
If I run without ?order= parameter, an expected NOTICE occours. Which due to be expected I do not need to informed about more than once.
However when in full debugging mode, I do wish to see the presence of undefined variables through the presence (or more interestingly absence) of said debug notices. -> That's what I think they are for. Avoiding isset brings language-implicit print statements.
Also realize this is about use cases where ordinary PHP form handling semantics are suitable, not application areas where strictness is a must.
Oh my, someone please help rewrite this. Lengthy explanation fail.
It is possible to develop a large PHP application that never emits any E_NOTICEs. All you have to do is avoid all situations where a Notice can be emitted, the vast majority of which are un-initialized variables and non-existist array keys. Unfortunately, this clashes with your wish to avoid isset() - and by extension array_key_exists() - because they are designed for handling that exact problem.
At best, you can minimize their use by careful framework building. This generally means (for example) an input layer which is told what GET variables to expect and what to default missing ones to. That way the page-specific code will always have values to look at. This is, in general, a worthwhile technique that can be applied to a variety of APIs. But I question whether this should be a high-priority design goal.
Unlike some other languages, PHP distinguishes between a variable not existing and containing a generally "empty" value (usually null). It is probably a design artifact from an earlier version, but it nonetheless is still present, so you cannot really avoid it.
I am using isset() only for $_GET and $_SERVER variables, where the data comes from outside the control of my application. And I am using it in some other situation when I don't have time to write a proper OOP solution to avoid it, but I'm sure that it can be avoided in most if not all places. For example it's better to use classes instead of associative arrays, this way you don't need to check the existence of an array key.
My advices are:
Avoid using the # operator.
Use Xdebug. First, it prints easily readable and easily noticeable messages about every notice/warnig, and it prints a very useful stack trace on exceptions (you can configure it to print out every method parameter and every local variable (xdebug.collect_params=4 and xdebug.show_local_vars=on configuration parameters). Second, it can disable the # operator with xdebug.scream=1 config value. You can use Xdebug for profiling and for code coverage analysis as well. It's a must have on your development machine.
For debugging, I am also using FirePHP, because it works with Firebug, and is able to print messages to the Firebug console, so it can be used for AJAX debugging as well.
With a custom error handler, you can catch and filter any error and warning, and you can log them into a file or display them with FirePHP, or you can use for example jGrowl or Gritter to nicely display them on the web page.
I am using a modified version of the example in the PHP manual:
<?php
//error_reporting(0);
set_error_handler("errorHandler");
function errorHandler($errno, $errstr, $errfile, $errline)
{
echo "errorHandler()<br />\n";
// filter out getImageSize() function with non existent files (because I'am avoiding using file_exists(), which is a costly operation)
if ( mb_stripos($errstr, 'getimagesize') !== false )
return true;
// filter out filesize() function with non existent files
if ( mb_stripos($errstr, 'filesize') !== false )
return true;
// consoleWriter is my class which sends the messages with FirePHP
if (class_exists('consoleWriter'))
consoleWriter::debug(array('errno'=>$errno, 'errstr'=>$errstr, 'errfile'=>$errfile, 'errline'=>$errline, 'trace'=>debug_backtrace()), "errorHandler");
switch ($errno) {
case E_USER_ERROR:
$out .= "<b>FATAL_ERROR</b> <i>$errno</i> $errstr<br />\n";
$out .= "Fatal error on line $errline in file $errfile";
echo "</script>$out"; // if we were in a script tag, then the print is not visible without this
//writeErrorLog($out);
echo "<pre>";
var_export(debug_backtrace());
echo "</pre>";
exit(1);
break;
case E_USER_WARNING:
$out .= "<b>WARNING</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
case E_USER_NOTICE:
$out .= "<b>NOTICE</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
default:
$out .= "<b>Unknown</b> <i>$errno</i> $errstr<br />\n";
$out .= "On line $errline in file $errfile<br />\n";
break;
}
if (!class_exists('consoleWriter'))
echo $out;
//writeErrorLog($out);
//addJGrowlMessage($out);
// Don't execute PHP internal error handler
return true;
}
function testNotice($a)
{
echo $a;
}
testNotice();
One more advice is not to use the closing ?> tag at the end of the php-only files, because it can cause headers already sent errors on configurations where the output buffering is disabled by default.
Well, if you wait for PHP 7, you'll have access to the null coalesce ternary operator, which, in addition to having the coolest operator name in existence (I'm naming my next kid "Null Coalesce") will let you do this:
$var = $some_array[$some_value] ?? "default value";
Which replaces the ubiquitous (and ugly)
$var = isset( $some_array[$some_value] ) ? $some_array[$some_value] : "default_value";
try xdebug - http://www.xdebug.org/docs/stack_trace
lots of isset checking does not harm u,
in fact, it encourage declare variables before use it
I think following the best practice is not waste of time. That's true, a notice is not an error, but with correct variable declaration and validation your code could be more readable and secure.
But it's not so complex to write a user-defined error handler with debug_backtrace sort the E_NOTICE(8) with a regexp.
I had a similar desire. So I started using custom error handlers.
http://php.net/manual/en/function.set-error-handler.php
You can then create your own filters/mechanisms for displaying/logging errors/notices.
Cheers!
PHP is definitely broken around this making code less readible. "null" means "undefined" - simple enough.
Here is what I do when I run into this problem making code unreadable:
/**
* Safely index a possibly incomplete array without a php "undefined index" warning.
* #param <type> $array
* #param <type> $index
* #return <type> null, or the value in the index (possibly null)
*/
function safeindex($array, $index) {
if (!is_array($array)) return null;
return (isset($array[$index])) ? $array[$index] : null;
}
// this might generate a warning
$configMenus = $config['menus'];
// WTF are you talking about!! 16 punctuation marks!!!
$configMenus = (isset($config['menus']) ? $config['menus'] : null;
// First-time awkward, but readible
$configMenus = safeindex($config, 'menus');
Cross posting this answer here. Does this help spam-checker?
The best way to avoid isset() in my opinion is to define your variables before you use them. I dislike isset() not so much because it's ugly but because it promotes a bad programming practice.
As for error handling itself, I put all that information out to the server logs. I also use php -l on the command line to syntax check the programs before hand. I make pretty messages for the users by default.
You might look into one of the various frameworks to see if any of them would work for you. Most of them I've looked at have error handling routines to make things easier than what PHP offers out of the box.
EDIT:
#mario - my response to your comment was getting too long :-). I don't advocate defining types or going to some kind of strict format like Java or C. I just advocate declaring the variable in the context that it's used. ( $foo = null; is not the same as leaving the variable blank).
I think this is more of a problem with global variables in a lot of cases, especially the super globals for getting GET and POST data. I really wish that PHP would drop super globals in favor of an class for getting input data. Something like this (super simple but hey you wanted something concrete: :) )
<?php
class PostData {
private $data;
public function __construct() {
$this->data = $_POST;
unset($_POST);
}
public function param($name, $value = null) {
if( $value !== null ) {
$this->data[$name] = $value;
}
if( isset( $this->data[$name] ) ) {
return $this->data[$name];
}
return null;
}
}
?>
Include the class then you can get and set POST data from the param() method. It would also be a nice way to incorporate validation into the input data. And as a bonus, no checking everything for isset() (it already is).
It's kind of an outdated answer now, but I originally used a flexible log dispatcher back then, https://github.com/grosser/errorhandler (Not exactly what I was looking for IIRC, but at least a little more sophisticated than alternating between complete and partial supression.)
Anyway, I'm meanwhile using a $_GET->int["input"] wrapper for the most common cases. Which is just a trivial ArrayAccess wrapper, implicitly catches non-existant vars, that allows easier notice recovery. (Just a by-product. Primarily meant for immediate filtering though.)
And for another project I'm even using a preproccessor macro IFSET#($var), to allow enabling/disabling or log-redirection depending on build parameters.

PHP and undefined variables strategy

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>

Categories