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 #?).
Related
First off I know this question has gone around more than once here:
Why should I fix E_NOTICE errors?
Why should I fix E_NOTICE errors? Pros and cons
But the more that I fix all E_NOTICEs (as people say you should) the more I notice that:
I am micro-optimising
I am actually making more code and making my code harder to mantain and slower
Take an example:
Say your using the MongoDB PHP driver and you have a MongoDate object in a class var named ts within a class that represents a single row in a collection in your database. Now you acces this var like: $obj->ts->sec but PHP throws a fit (E_NOTICE) because ts in this case is not defined as an object in itself because this particular row does not have a ts field. So you think this is OK, this is desired behaviour, if it's not set return null and I will take care of it myself outside of the interpreters own robotic workings (since you wrap this in a date() function that just returns 1970 if the var is null or a none-object).
But now to fix that E_NOTICE as another developer really wants me to since having ANY E_NOTICEs is terribad and it makes the code slower to not do it according to the errors. So I make a new function in the $obj class called getTs and I give it 3 lines, literally to do nothing but check if the ts var is a MongoDate object and return it if it is...
WHY? Can't PHP do this perfectly fine for me within its much faster interpreter than having to do it within the runtime of the app itself? I mean every where I am having to add useless bumpth to my code, pretty much empty functions to detect variables that I actually just handle with PHPs own ability to return null or checking their instanceof when I really need to (when it is vital to the operation and behaviour of the said function) and don't get me started on the isset()s I have added about 300 lines of isset()s, it's getting out of hand. I have of course got to make this getTs functions because you can't do:
class obj{
public $ts = new MongoDate();
}
I would either have to store the ts within the __constructor (which I am not too happy about either, I am using a lot of magics as it is) or use a function to detect if it's set (which I do now).
I mean I understand why I should fix:
Undefined vars
Assigning properties of unset vars (null vars)
constant errors etc
But if you have tested your code and you know it is safe and will only work the way you desire what is the point in fixing all of the undefined index or none-object errors? Isn't adding a bunch of isset()s and 2 lines functions to your code actually micro-optimisation?
I have noticed after making half my site E_NOTICE compliant that actually it uses more CPU, memory and time now...so really what's the point of dealing with every E_NOTICE error and not just the ones that ARE errors?
Thanks for your thoughts,
You do certainly do get better performance by using isset(). I did some benchmarks, not too long ago, and just hiding errors came out to be about 10x slower.
http://garrettbluma.com/2011/11/14/php-isset-performance/
That said, performance usually isn't a critical factor in PHP. What does, personally drive me crazy is silent errors.
When the interpreter chooses to not flag something as an error (which could lead to instability) is a huge problem. PHP in particular has a tendency to
warn about things that should error (e.g. failure to connect to database) and
issue notices about things that ought to warn (e.g. attempting to access a member of a null object).
Perhaps I'm just overly opinionated about this kind of stuff but I've been bitten before by these silent errors. I recommend always including E_NOTICE in error reporting.
Whether or not you should fix them is certainly debatable, and will just depend on the return in your situation; eg, it's more important if the code will have a longer life-span, more devs, etc.
In general, assuming that your functions will be used (and mis-used) by someone else is the best practice, so you should do isset/!empty/is_object checks to account for this. Often, your code will find it's way into uses and situations you never intended it for.
As far as performance, Every time any kind of error is thrown--E_NOTICE included--the interpreter spins up the error handler, builds a stack trace, and formats the error. The point is that, whether or not you have them reporting, errors always slow execution; therefore, 2-3 function calls to avoid an E_NOTICE will still improve your performance.
Edit:
Alternatives for the above example
I wouldn't necessarily create extra objects to avoid the errors; you can gracefully avoid them without. Here are a couple of options:
1) Function that handles missing ts:
SpecialClass class {
funciton getTs () {
return !empty($this->ts) ? $ts->sec : false;
}
}
2) Deal with missing ts in template/procedure:
if (!empty($obj->ts->sec)) {
//do something
}
I particularly like empty() because you can use it to replace of (isset($var) && ($var or 0 != $var //etc)), saving multiple calls/comparisons and empty never throws notices for the target var or attribute. It will throw an error if you're calling it on a proptery/member of a non-existent variable.
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
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.
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>
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;
}