Since i changed my error reporting level to error_reporting(E_ALL | E_STRICT); I am facing this error. I can obviate from this error using isset() but the code looks so ugly!
So my question is: What if I go back to my normal settings of error reporting? does it really matter to know that something is not already defined? because it woks properly without the Notice error.
Because i have +10 inputs and i get them like that:
$username = $_POST['username'];
I also tried to pre-define the variables using this in the top on the file.
$username = null; and $username = 0; but they don't work.
Thanks.
It does matter. Errors slow down PHP and you really should design you application not to throw errors. Many other languages will completely die in situations where PHP happily continues script execution.
When developing, your script should not throw any errors (even an E_NOTICE).
I would suggest creating a simple function to grab the $_POST values and do the checking for you.
e.g.
<?php
function getPost($key)
{
return isset($_POST[$key]) ? $_POST[$key] : null;
}
Edit:
Apparently it wasn't clear to the OP how to use this:
$username = getPost('username');
It means there is no key 'username' in the POST array.
Generally, it is a good idea to check and correct these things, as they may ripple to other parts in your application that do depend on the missing value.
It does matter -- when I get strange behaviour in a php application the error log is the first place I look and nine times out of ten an "UNDEFINED INDEX" message leads me straight to the root cause.
Notices do have a purpose: they're a tool to detect potential errors in your code. If you write code that triggers notices for trivial operations and you are not willing to change it, you'll have to disable notice reporting and thus reject a helpful tool on purpose and make your work harder than needed.
Historically, PHP was designed with extreme simplicity in mind (in old versions you'd just have an $username available with zero lines of code) but this approach proved highly inadequate as the web evolved: it only lead to code that was insecure and hard to maintain.
All errors should be addressed, no matter the level, for portability.
If you build your application not addressing strict errors, and your application is deployed on a server that does have strict error reporting, your application is going to fall over pretty quickly.
Your best bet is to check the existence of $_POST['username'] and then act independently on that return value. Using isset() your return value with either be true or false.
I'm guessing $_POST['username'] is for use in an authentication system of some description? Therefore, if your isset() function returns false you could then display an error detailing to the user that username is required.
Related
While my site was working without any problem I suddenly started to have a really high CPU usage on my server so I started to check the code more carefully and enabled E_ALL error reporting.
Then I found out I had a great many of this "notices":
Notice: Undefined index: userID in /var/www/vhosts/mydomain.com/httpdocs/header.php on line 8
Most or them refer to unset cookies, for example this:
$uid = $_COOKIE['userID'];
If the user is unlogged I get a notice right there, and every time I use $uid.
What I want to know if this: Are this notices harmless or can they really cause any problems in my site? (Speed issues, errors etc.)
It is a notice only, try this code:
$uid = isset($_COOKIE['userID']) ? $_COOKIE['userID'] : 0;
It is not hamless (depending on the point of view), and you can disable this with error reporting functions, otherwise, the correct way is verify if index exists isset($_COOKIE['userID']) and if not, define a default value (null for instance)
$var = isset($foo) ? $foo : 'default';
You need to verify if variable exists, if you don't known it exists or not.
$var = 'foo'
if($var == 'foo') { // I known $var is defined, because I have defined it.
[..]
}
/**
* Above, I don't known if user go to mywebsite.com/index.php or
* mywebsite.com/index.php?foo=bar, so, I need to verify if index is defined
*/
if(isset($_GET['foo']) && $_GET['foo'] == 'bar') {
[...]
}
Those notices will cause a little bit of a speed problem, because raising a notice costs some extra effort.
The main problem though is that this is a serious error. You are trying to work with something that doesn't exist. This may or may not lead to Bad Things Happening, but it means your program is not correct. Since you should always develop with error reporting on full power to see and solve actual problems, notices about undefined indexes or undefined variables are serious and need to be solved. Anything that PHP complains about is serious and needs to be solved. See The Definitive Guide To PHP's isset And empty.
Notices are in general harmless, yet they may indicate a poor application design. In general it is always a good idea to utilize available PHP tools (i.e isset($someVar)) to make sure that your business logic is taking proper care of variable initialization. When you see no such notices with E_ALL error reporting setting, it's always better.
The Notice warning is in the first point of view harmless, but you should keep in mind, that the programming is not right and it might be causes errors on following lines.
In your example it es better to use
$uid = isset($_COOKIE['userID'])?$_COOKIE['userID']:0;
So you can be sure, that $uid always has a value and when the value greater then 0 you have a falid userId ...
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
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>
Python's convention is that variables are created by first assignment, and trying to read their value before one has been assigned raises an exception. PHP by contrast implicitly creates a variable when it is read, with a null value. This means it is easy to do this in PHP:
function mymodule_important_calculation() {
$result = /* ... long and complex calculation ... */;
return $resukt;
}
This function always returns null, and if null is a valid value for the functuion then the bug might go undetected for some time. The Python equivalent would complain that the variable resukt is being used before it is assigned.
So... is there a way to configure PHP to be stricter with variable assignments?
PHP doesn't do much forward checking of things at parse time.
The best you can do is crank up the warning level to report your mistakes, but by the time you get an E_NOTICE, its too late, and its not possible to force E_NOTICES to occur in advance yet.
A lot of people are toting the "error_reporting E_STRICT" flag, but its still retroactive warning, and won't protect you from bad code mistakes like you posted.
This gem turned up on the php-dev mailing-list this week and I think its just the tool you want. Its more a lint-checker, but it adds scope to the current lint checking PHP does.
PHP-Initialized Google Project
There's the hope that with a bit of attention we can get this behaviour implemented in PHP itself. So put your 2-cents on the PHP mailing list / bug system / feature requests and see if we can encourage its integration.
There is no way to make it fail as far as I know, but with E_NOTICE in error_reporting settings you can make it throw a warning (well, a notice :-) But still a string you can search for ).
Check out error reporting, http://php.net/manual/en/function.error-reporting.php
What you want is probably E_STRICT. Just bare in mind that PHP has no namespaces, and error reporting becomes global. Kind of sucks to be you if you use a 3rd party library from developers that did not have error reporting switched on.
I'm pretty sure that it generates an error if the variable wasn't previously declared. If your installation isn't showing such errors, check the error_reporting() level in your php.ini file.
You can try to play with the error reporting level as indicated here: http://us3.php.net/error_reporting but I'm not sure it mention the usage of non initiated variable, even with E_STRICT.
There is something similar : in PHP you can change the error reporting level. It's a best practice to set it to maximum in a dev environnement. To do so :
Add in your PHP.ini:
error_reporting = E_ALL
Or you can just add this at the top of the file your are working on :
error_reporting(E_ALL);
This won't prevent your code from running but the lack of variable assignments will display a very clear error message in your browser.
If you use the "Analyze Code" on files, or your project in Zend Studio it will warn you about any uninitialized variables (this actually helped find a ton of misspelled variables lurking in seldom used portions of the code just waiting to cause very difficult to detect errors). Perhaps someone could add that functionality in the PHP lint function (php -l), which currently only checks for syntax errors.