Php: about echoing a null variable - php

I'm currently learning php using Murach (the book, published in 2010). One of the exercises has these statements:
<label>Investment Amount:</label> <input type="text" name="investment"
value="<?php echo $investment; ?>"/><br />
<label>Yearly Interest Rate:</label> <input type="text" name="interest_rate"
value="<?php echo $interest_rate; ?>"/><br />
<label>Number of Years:</label> <input type="text" name="years"
value="<?php echo $years; ?>"/><br />
The whole gist is that the value attributes above with the echo statements have variables which have not been assigned any value at first, so the textbox is supposed to be empty according to the book. But later on the exercise this same page will be called again and the variables will now have values, thus they will be printed on the textbox. Here's the book's explanation:
These echo statements display the variables that contain the data that
the user has previously entered into the form. The first time this
page is displayed, though, these variables won’t contain data so the
text boxes will be empty.
However, upon running the program for the first time, the textboxes are in fact not empty:
Since this book was published 5 years ago I'm guessing either they worked then but do not now, or the code itself is wrong. Can anyone tell me if this is just obsolete code or is it really broken to begin with? And how can I fix it to get the desired effect of an empty textbox using a null variable?
Thanks!

You should check if they are defined.
i.e.
<?php echo (isset($years)) ? $years : ''; ?>
Also, if you turn off display_errors in your php.ini this won't happen, however this would be an ill-advised solution

The most important way of programming is programming in such a way, that someone else can also understand it. So in that case, if you plan to use this variable, declare and comment it before:
$investment = ''; // Future post investement variable, on startup empty
$interest_rate = ''; // Future interest_rate variable, on startup empty
$years = ''; // Future years variable, on startup empty
In that case everyone is sure what each variable is, and what it will contain. And no undefined error will occur.
Also notice that turning off warning display, as mentioned in comments and answers, isnt a good idea. When you write nice code, no warnings should be displayed. And turning them off is of course not a solution.
The only MUST do is to turn off warnings and errors on production, to not give hackers any possible clue, even if something goes wrong. And save them in some sort of error logger.
If you plan to use this variable with post, I suggest doing something like that:
$investement = (isset($_POST['investment'])) ? safety($_POST['investment']) : '';
Where safety is your own safety check function (remove special characters, and prevent mysql injection if you plan to echo / store data). It is the same as writing:
if (isset($_POST['investment'])) {
$investement = safety($_POST['investment']);
}
else {
$investement = ''; // init value
}

A Notice is what it is, a notice, it doesn't prevent your code from executing as such. Of course if the variable / code generating the notice is used elsewhere you can run into trouble.
So, the book is somewhat right, but I would say that it's bad practice since that you should always aim to have 0 warnings / notices, which means that you should do as #Swifty mentioned and check whether the variable is set.

Related

Why should i use isset? [duplicate]

This question already has answers here:
Weak typing in PHP: why use isset at all?
(9 answers)
Closed 7 years ago.
I'm beginner in PHP and was wondering what's the difference between this
$variable = "text";
if($variable){
echo $variable;
}
and this
$variable = "text";
if(isset($variable)){
echo $variable;
}
Sometimes you want to know if a variable is set or not e.g. for security reasons of for debugging reasons.
The function isset() is used to determine if a variable is set and is not NULL and is accordingly returning true or false.
The expression if($variable) {} instead will evaluate to false if $variable is set but is zero or if $variable is set but its current value is false (=counterexample)
Assume:
isset($variable): Evaluates to true if a variable is set and not null
if($variable): Evaluates to true depending on the value of a variable or the result/value of an expression
The most important feature of functions like isset(), empty(), etc. to me is, that they do not throw errors when a variable is not set, like Marc B already mentioned.
PS: I strongly recommend to turn on strict mode and all error reporting during development.
isset is used to check whether input you receive contains what you expect - this is a very, very loose definition and I wrote that trying to explain easily when you'd use it.
When you set a variable yourself, then it doesn't make sense to use isset, you know it's set and that it contains some value.
However, many languages, not just PHP, deal with user input. User in this case could be a human, another computer service etc. You usually store that input inside a variable. A great example is PHP's $_POST, $_GET, $_SERVER, $_SESSION.
When you receive an input that user made via HTML form, you want to check whether certain values have been populated - in that case, you use isset.
An example HTML form:
<form method="POST" action="your_file.php">
<input type="text" name="first_name" />
<input type="text" name="last_name" />
<button type="submit">Send</button>
</form>
Someone can submit that form, they can fill in both inputs. Or only one of them, or even none. You don't know what they've done, but regardless - PHP will provide you with a variable that might contain correct input.
If I submitted that form with nothing filled in, and if you tried to access a value for first_name - you would get a PHP warning - and you don't want PHP warnings.
Therefore, before working with user input (in this case with a $_POST superglobal array), you would check whether I filled in everything properly and you'd do that with:
if(isset($_POST['first_name']) && isset($_POST['last_name']))
{
echo "Form was filled in correctly";
}
else
{
echo "Form wasn't filled in correctly! Please fill in both fields";
}
Hopefully that clears it up a bit. Just once more, I used very trivial but real-world examples.
Perhaps you example is a bit skewed. However. if you were to ignore the first line of each code segment, perhaps you will see this differently. Consider the code segments
if($variable){
echo $variable;
}
If $variable has not been initialised and assigned a value, then the is statement will result in an error.
On the other hand, if you initialise the variable
$variable = "text";
if($variable){
echo $variable;
}
will test is the variable is true, or non zero.
The isset() function will ignore the value, and tell you if the variable is initialised.
In the following code segment, the if() statement will return true.
$variable = "text";
if(isset($variable)){
echo $variable;
}
while, in this code
<?php
if(isset($variable)){
echo $variable;
}
the if() statement will return false.

onblur not returning the most updated value

Please excuse my ignorance. I want to always retain the current value (that I have supplied by changing the default value) in the input box when I click outside the text box. But the following code returns to the default value if after modification I again click the text box and then click outside the text box. But I want to retain the most updated value always in the textbox.
Perhaps I have to make changes in the area this.value=' <?php echo "$r1[MAJORS1]" ?>';, but not understanding how to do that.
Any help please
onfocus="if(this.value!=''){ this.value=''; this.style.color='#000';}"
onblur="if(this.value==''){ this.value='<?php echo "$r1[MAJORS1]"?>'; this.style.color='#000';}"
I believe you're looking for:
<input type="text"
data-value="<?php echo htmlentities("$r1[MAJORS1]"); ?>"
placeholder="<?php echo htmlentities("$r1[MAJORS1]"); ?>"
onfocus="if(this.value!=''){
this.value='';
this.style.color='#000';
this.setAttribute('placeholder',this.getAttribute('data-value'));
}"
onblur="if(this.value==''){
this.value=this.getAttribute('data-value');
this.style.color='#000';
}else{
this.setAttribute('data-value',this.value);
}"
value="<?php echo htmlentities("$r1[MAJORS1]"); ?>">
Not exactly pretty though. Messing with the default functionality of the user's browser has a tendency to confuse. I believe my placeholder usage, though, will make it less confusing for the user that their input will revert to whatever the placeholder reads.
See my jsfiddle here: http://jsfiddle.net/3Lvs77bv/
I don't, however, know if MAJORS1 is supposed to be a constant or a key in your $r1 array, though. If it's a key, make sure to quote it to prevent warnings otherwise PHP will think it's a constant. But PHP will fallback, in any case, if the constant isn't defined and treat it as a key in the array, although will generate warnings.
Edit:
If you'd like to allow for blank values, you could either add a button to clear the field like so:
http://jsfiddle.net/3Lvs77bv/1/
Or, as I'd suggest, simply get rid of all the clutter you're trying to code, which affect the user's default browser functionally, and simply use this.select() instead when the field is focused:
http://jsfiddle.net/3Lvs77bv/2/

I'm confused about the flow of $_POST[] variables and regular variables

I have a simple form I created, and in it I have the following checkbox:
<input type="checkbox" name="test">
Note: this form is being submitted to itself.
Above the form, I have the following PHP:
if (empty($_POST['test'])) {
$thevalue = 0;
} else {
$thevalue = 1;
}
var_dump($thevalue);
When I process the form, I get what I would expect. If I check the box and submit, I get int(1) if I leave it unchecked I get int(0).
In the first line of my PHP code, I wanted to replace $_POST['test'] with some simple variable.
So I added the following line above my code:
$simplevar = $_POST['test']
I then replaced the condition in my if statement to be empty($simplevar)
But when I submit the form, I get a "Notice: Undefined index:" error message
Why is this happening?
Assuming it's possible to achieve what I was after (i.e. insert $_POST into $simplevar), how might I go about it?
Thanks in advance for your help!
PS: I may have a follow up to this question, but didn't want to clutter things by jamming it all in here.
Thanks again... oh, and Merry Christmas! ;-)
This happens because when you don't check the checkbox, the browser does not send any value to server for that control when the form is submitted. Because of this, $_POST['test'] is not defined, and you tried to use it without a check as to whether it existed, so you get a warning. One of the checks that empty() does is to see whether the value is set. So, when you use the $_POST keys directly in empty(), you don't get an error, but when you try and use it in an assignment without this check, you will get the error.
You can do roughly what you want to do, you just have to change the logic slightly. If you do:
$simplevar = !empty($_POST['test']);
// You could also do
// $simplevar = isset($_POST['test']);
if ($simplevar) {
// The box was checked
} else {
// The box was not checked
}
...it will do what you want without the error. Using this approach, $simplevar always holds a boolean indicating whether or not the box was checked.
When a checkbox is unchecked, it's not added to the $_POST array as a key, which is why $simplevar = $_POST['test'] returns the error you posted. Using empty() gets past this problem by empty() handling errors better (well, silently at any rate).
You haven't specified whether you get that error when the checkbox is checked or not, but the above explanation is the only one I can give. If you're unsure, try doing print_r($_POST) to see what $_POST actually contains.
A solution to your problem would be to use a ternary expression to handle the error a little better:
$simplevar = isset($_POST['test']) ? 0 : 1;
This will assign 0 to $simplevar if $_POST['test'] isn't set (checkbox isn't checked), or 1 otherwise.
Do make sure all your form processing code is put inside
if(!empty($_POST)) {
// Code
}
So that it's not executed every time the page loads, otherwise your error will show every time.
Checkbox values are only transmitted if the checkbox was checked. This means that unchecked checkboxes won't appear in the $_POST array.
A way to suppress the notice from PHP is to use a reference instead of a variable:
$simplevar =& $_POST['test'];
if(empty($simplevar)) $thevalue = 1;
else $thevalue = 0;
That's expected behaviour. If you are assigning the variable like this:
$simplevar = $_POST['test'];
Then the $_POST variable might be absent. The Zend runtime then assigns the NULL value, but gives you a useful debug hint, should that not be what you wanted.
When you used empty() before, the check for variable existence was built in. empty() is a language construct. Like isset() it's often used to eschew such notices. The cumbersome syntax to emulate such language behaviour is:
$simplevar = empty($_POST['test']) ? NULL : $_POST['test'];
The language built-in for is:
$simplevar = #( $_POST['test'] );
Now, I will get roasted for mentioning it. (Using # is useful if you want to bring the debug notices back at some point, while the empty and isset constructs eternally suppress them.)
First, you should always check that variables in $_POST, $_REQUEST, and $_GET are set before attempting to use them. Always handle the condition where they are not set even if you simply output an error.
Because the error is an undefined index it seem the error is in test not being set in $_POST, though that doesn't make a lot of sense. I would add a check, maybe an echo or var dump to check $_POST. If it is set the other problem could be an issue with scope. $_POST is something called a super global which makes it available in any scope. Variables you set you may need to make global by defining them as such if you want to access them across scopes.

Is it alright to suppress/hide PHP notices?

I've suppressed notices for quite some time with no problems whatsoever but I am beginning to wonder if I'm doing the right thing. I can't seem to find any logical reason why I shouldn't just suppress them but some other people seem to think that suppressing them using error_reporting is a horrible thing to do, but why?
The closest thing to an answer I could find was in this question but that's still far from the answer I'm looking for. Is there some sort of unforeseen downside to hiding all the notices that PHP generates? For example, to include a variable from a POST call back into the form because there were errors, I would simply use:
<?= $_POST['variable'] ?>
This would generate a PHP notice. To fix that notice, I could use something like this:
<?= isset($_POST['variable']) ? $_POST['variable'] : '' ?>
But, is this really necessary? Will my code actually benefit any from doing this rather than just echoing the variable whether it exists or not and potentially creating a PHP notice? It seems to me that being able to ignore notices is a benefit of using PHP as then you don't have to worry about whether a variable is defined or not, especially for an example such as this where it doesn't seem to matter.
I also take advantage of PHP's ability to automatically change a variable's type/casting depending on how it's being used and you will often find code snippets such as this:
for ($i = 0; $i < $limit; $i++) $results[] = $i; // Example
where $results has not been previously defined, but is turned into an array when I try to add a new item to it as an array. I sort of prefer doing it this way because if no results are added to the array and I need to store that information or convert it to JSON for whatever reason, then that particular variable will not be defined and thus save additional bandwidth, even if it's minute.
$data = stdClass; // For reference, in my case this would be defined before this code
$data->results = array();
$limit = 0;
for ($i = 0; $i < $limit; $i++) $data->results[] = $i;
print json_encode($data);
// {"results":[]}
versus
$data = stdClass; // For reference
$limit = 0;
for ($i = 0; $i < $limit; $i++) $data->results[] = $i;
print json_encode($data);
// []
The question again: what real benefit, if any, do I gain from fixing notice errors rather than just suppressing them? How can/would it harm my code?
In my point of view, you should never suppress errors, any kind of them, notices or not. It might give you some convenience right now, but down the road, you'll face many, many problems with your code when you are maintaining it.
Suppose you have a variable you want to echo out like the above first example. Yes, using isset is a little complicated, but maybe your application should handle the special empty case anyway, thus improving the experience. Example:
if (isset($var)) {
echo $var;
} else {
echo "Nothing is found. Try again later.";
}
If you only had echo $var; and if this was a public facing view a user was reading, they would just see nothing there, which may cause confusion. Of course, this is just one special case where fixing PHP Notices can improve your application.
It shouldn't be taken as a trouble or inconvenience when you are taking care of notices in PHP code, because code is supposed to be clean. I'd rather have a notice-free code than seeing clean code when I open it in source. Of course, both is definitely better! :)
Again, the errors (even if they aren't fatal) will cause problems down the road. If you're already doing things like echo $var; without checking it, that's an assumption that a variable exists, even if you know it might not, it will just give you a habit of assuming things exist and work. This might be small right now, but after a while you'll find out that you'll cause yourself many, many problems.
The notices are there for a reason. If we all did error_reporting(E_ALL ^ E_NOTICE) in our code, we're just being irresponsible for our code. If you are able to fix it, then why are you being lazy and not doing so? Sure, ship 1.0 with notices, fix them later, that's what we all say. But it is better to do that as a habit, code perfect the first time. If you spend 15 minutes writing code plagued by notices, and then spend 2 hours in later development time fixing them, why not just spend an hour and a half perfecting the code as you write it in the first place?
Writing good code should be a habit, not an inconvenience.
Error messages are there for a reason. Respect them, fix them, and there you go, you're a responsible programmer.
You also pave a path for the future maintainers of your code.
Suppose that you have a notice that you shouldn't ignore.
This notice will be hidden into all notices that you usually ignore.
IMHO, warnings should not be ignored. You should always take care of warnings to prevent bug. Every time I have a notice in my log file, I treat it like a bug.
Also, if your site is accessed by a lot of user, you'll get a very big log file.
In my experience, notices usually indicate a good chance that there's a bug somewhere in your code, usually of the case where you expect a certain variable to be set at a certain point but there will be cases where it isn't, and you'll start wondering why some part of your page isn't showing up or starts crashing randomly.
Of course computers aren't all that smart, and there will be cases where the code is clear enough and you don't care if there are any warnings, but that's what the # operator is for.
I respectfully disagree with some of the comments that suggest that you should never suppress notices. If you know what you are doing, I do think using # is very useful, especially for handling unset variables or array elements. Don't get me wrong: I agree that in the hands of an inexperienced or sloppy programmer, # can be evil. However, consider this example:
public function foo ($array) {
if (isset ($array[0])) {
$bar = $array[0];
} else {
$bar = null;
}
// do something with $bar
}
is functionally identical to
public function foo ($array) {
$bar = #$array[0];
// do something with $bar
}
but is IMHO less readable and more work to type. In these types of cases, I know there are exactly two possibilities: a variable is set or it isn't. I don't know in advance, but I must proceed in both cases. I see nothing wrong with using # in that case. Yes, you could also write
public function foo ($array) {
$bar = isset ($array[0]) ? $array[0] : null;
// do something with $bar
}
but I find that only marginally better. To me, code readability and brevity are values in and of themselves, and bloating the code with isset-tests just out of principle to me is a little silly.
Of course, if I am not mistaken, using # takes a tiny bit more time to execute that an isset-test, but let's be honest: how much of our code is truly performance critical? In a loop that is executed a bazillion times, I would probably use isset instead, but in most cases, it makes no difference to the user.

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