for loop with isset() != null - why? - php

for($i=0; isset($_POST['key_str'][$i]) != null; $i++)
{
// some php here
}
I've inherited some legacy code at work and I've found above for() loop in several places. I've been writing PHP, Javascript and Python for years now and have never seen anything like this. My gut tells me this is the person who wrote this legacy code came from a different language. And may have not been very experienced.
Questions:
1) Does isset($_POST['key_str'][$i]) perform better than count($_POST['key_str'])?
2) Does this resemble syntax that you'd typically find in another language? If so, which language?

Inside isset, $i (which is incremented in the loop) is used in this expression. $_POST['key_str'][$i], which is part of the check.
So basically, $_POST['key_str'] is expected to be an array, and this loop will loop over all items in that array.
If you like, you could use count(), or replace the whole thing with a foreach loop, although that may result in a warning if $_POST['key_str'] is not set at all or is not an array. isset is a very easy way to get around that, because it handles all those situations and will return false, so the loop will simply not be entered in that scenario.

isset() is a language construct that returns a boolean, thus it can never be null. However, the comparison uses the equal operator (==) rather than the identical operator (===) thus type juggling applies:
Type of Operand 1 Type of Operand 2 Result
bool or null anything Convert both sides to bool
… and null casts to boolean false so:
true != null → true != false → true
false != null → false != false → false
Thus the loop is equivalent to:
for($i=0; isset($_POST['key_str'][$i]); $i++){}
In other words, != null is redundant and harms readability.
Now, square brackets are used to read an array element by key or a string byte by offset. Since $_POST is an external variable the loop can actually do both—I presume the former was intended. Without further context it's impossible to say what it's meant to accomplish or how to rewrite it but I suspect it's a convoluted alternative to foreach().
So to answer your questions:
It's irrelevant. They do entirely different things.
This is opinion-based (to me, it's the syntax of someone who's not familiar with programming in general.)

Related

Why do functions execute in PHP if statements?

So the syntax for if statements is:
if(condition){
//code to execute
}
Then why do functions when placed in place of conditions work in PHP.
In PHP (and many languages) there is no specific concept of a "condition"; the actual definition of an if statement is:
if(expression){
//code to execute
}
An "expression" is simply anything that can be evaluated and results in a value. A single value, like 42 is an expression on its own, as is a simple sum like 1 + 1. A function call like strlen('hello') is also an expression, evaluating to the result of the function; the function has to be run, which may have side effects, to determine that result. Expressions can be arbitrarily complex by linking then with operators, like strlen('hello') * 2 + 1.
Commonly in an if statement, you'd have something like $foo === $bar - this is just an expression that uses the === operator to give a boolean result, either true or false. PHP will evaluate that expression, and then decide whether to run the conditional code based on the result. The expression can be as simple or complex as you want - if(true) is valid, though not often useful, and so is if((strlen('hello') * 2 + 1) > 10).
If the result of the expression is not a boolean, PHP "coerces" it into one, as described on the manual page about the boolean type. For instance strlen($foo) evaluates to an integer, and all integers other than zero coerce to true, so if(strlen($foo)) acts like if(strlen($foo) !== 0).
As well as function calls, there are other expressions which have side effects. For instance, an assignment can also be used as an expression, evaluating to the value assigned. This lets you do things like $foo = $bar = 0; where $foo is assigned the result of running $bar = 0; which is of course 0. It also lets you put assignments inside if statements, like if ( $result = getData() ) { ... }, which is shorthand for $result = getData(); if ( $result ) { ... } This technique should be used with care, though, because at a glance it can be hard to spot the difference between = (assignment) and == (weak comparison).
The values returned in a PHP if condition are not restricted to be "strictly" Boolean, however the condition is expected to be Boolean. Why? Because all PHP variables types (inbuilt or user-defined) can be implicitly type-casted (converted automatically) to Boolean. According to the PHP manual:
To explicitly convert a value to bool, use the (bool) or (boolean) casts. However, in most cases the cast is unnecessary, since a value will be automatically converted if an operator, function or control structure requires a bool argument.
The PHP manual also explicitly specifies the falsy values for the different variable types including user defined types with all other values not specified being truthy:
the following values are considered false:
the boolean false itself
the integer 0 (zero)
the floats 0.0 and -0.0 (zero)
the empty string, and the string "0"
an array with zero elements
the special type NULL (including unset variables)
SimpleXML objects created from attributeless empty elements, i.e. elements which have neither children nor attributes.
Every other value is considered true (including any resource and NAN).
Therefore, to explicitly answer your question:
why do functions when placed in place of conditions work in PHP?
One reason I know of, is so you can conveniently perform assignments in the conditions:
function inverse_power($base, $exp)
{
if($power = pow($base, $exp)) {
return 1/$power;
}
else {
return "logical error: you can't divide by zero";
}
}
echo inverse_power(2,1); // 0.5
echo inverse_power(0,1); // logical error: you can't divide by zero
From the above example, you see the feature saves me multiple lines of code. Note that $power is not explicitly Boolean, but will be automatically converted to Boolean only to test the condition. The actual value of $power still persists throughout the function.
Because a condition is a boolean and functions can return booleans. And for conditions to work, the condition itself has to be evaluated, so it can be a function that is executed also.

How to differentiate between null or "" and 0 in PHP?

I have a table of codes in a database. One of the codes has the id of 0.
I'm making a search function and I want one of the filters to be the codes, but it's optional. So, I need to differentiate between "0" and null in an if statement.
Here is one idea that looks to me like it would work...
if ( 0 < (int)$input['code'] or false !== strpos($input['code'], "0") ){
// filter the search with the code
}
From this answer to a general question there are not that many differences between 0 and null. isset() might be one but empty() will not work. I'm not absolutely sure if the input is null or "" after it has been processed, I think it may be "". If this is the case, isset() will not work either.
Is there a better way to differentiate between 0 and null/""?
Use the === and !== operators for these sort of comparisons. These "strict" or "true" comparison. These operators were invented specifically to help deal with the sort of comparison problems you've described.
You also might be interested in the PHP comparison tables. This docs page runs through a lot of the various edge cases in PHP equality.

Check if variable has value and isn't empty

I want to check if a numeric variable has a value (including '0') and is not empty. Empty meaning EMPTY (''), not '0'.
Is this really the best I can do with PHP?
if (isset($variable) && $variable !== '') { ... }
I'd like to do this with one check without writing a function for it...
What you are trying to check is string length, not "empty". This can easily be done using strlen().
if (isset($variable) && strlen($variable) > 0) {
// Do something
}
If you want to exclude whitespace as invalid, you can add a trim() in there as well (generally recommended).
if (isset($variable) && strlen(trim($variable)) > 0 } {
// ...
}
The best thing you could do, is making your own custom function. The point is to pass the variables by reference to not trigger a warning, when you pass an undefined variable. As posted as comment, I'd use something along the line isset($variable) AND !empty($variable) AND !is_numeric($variable) AND $variable !== false to cover all cases.
Your custom function could look like this (improved version):
function is_blank(&$variable) {
return (bool) !(isset($variable) AND (!empty($variable) OR is_numeric($variable) OR $variable === false));
}
https://3v4l.org/ZcCDu
Yes, your way is the best (most efficient) way to:
insure the variable has been set (so you don't get an warning checking a variable that's not been set)
it's not the empty string ''
But, could be '0', 0,false, null, or [] which all count as empty in php, but you wish to consider as non-empty as indicated by your OP
your !== will ensure only exactly the string '' is compared (no casting/conversion)
The use of strlen works as well, but if you look at the opcode generated you'll see direct comparison is more 3 times computationally more efficient (assuming all operations are equally weighted, even more efficient if operations like DO_FCALL take significantly more cycles to execute than a basic IS_NOT_IDENTICAL check)
The !== ''version bytecode:
IS_NOT_IDENTICAL ~1 !0, ''
The strlen() > 0 version bytecode:
SEND_VAR !0
DO_FCALL 1 $1 'strlen'
IS_SMALLER ~2 $1, 0
(The answer has been edited. Consult the additionals further down under "ternary operations").
Why go through the trouble of using all that?
Just use an "not empty" if(!empty($var)){...}
However, if you're using this with a GET array, then yes; it would be best to use an isset() and empty() on a conditional statement.
I want to check if a variable has a value (including '0') and is not empty
That to me interprets as:
Check if a value has a value and is not empty (as you wrote) and stands to contain a 0 (zero).
Therefore:
if(!empty($var) && $var='0'){...}
I'd like to do this with one check without writing a function for it...
Use a ternary operator then.
However "without a function"... right well you can't. You still need "some type of function".
About that "ternary operator" I mentioned above. You can reference what are called "nested ternary operations" in both these Q&A's on Stack:
How to concatenate multiple ternary operator in PHP?
nested php ternary trouble: ternary output != if - else
That way you won't need a custom function.
Sidenote: I am by far not taking away or trying to take away from (Charlotte's) accepted answer (which should remain as accepted). This is just an additional method of achieving your (ultimate) goal.

Several PHP type-juggling comparisons, such as empty string and an empty array, return unexpected results

The triple equal I think everyone understands; my doubts are about the double equal. Please read the code below.
<?php
//function to improve readability
function compare($a,$b,$rep)
{
if($a == $b)
echo "$rep is true<br>";
else
echo "$rep is false<br>";
}
echo "this makes sense to me<br>";
compare(NULL,0,'NULL==0');
compare(NULL,"",'NULL==""');
compare(NULL,[],'NULL==[]');
compare(0,"",'0==""');
echo "now this is what I don't understand<br>";
compare("",[],'""==[]');
compare(0,[],'0==[]');
compare(0,"foo",'0=="foo"');
echo "if I cast to boolean then it makes sense again<br>";
compare("",(bool)[],'""==(bool)[]');
compare(0,(bool)[],'0==(bool)[]');
?>
Output:
this makes sense to me
NULL==0 is true
NULL=="" is true
NULL==[] is true
0=="" is true
now this is what I don't understand
""==[] is false
0==[] is false
0=="foo" is true
if I cast to boolean then it makes sense again
""==(bool)[] is true
0==(bool)[] is true
I would expect an empty array to be "equal" to an empty string or to the integer 0. And I wouldn't expect that the integer 0 would be "equal" to the string "foo". To be honest, I am not really understanding what PHP is doing behind the scenes. Can someone please explain to me what is going on here?
The simple answer is that this is the way php has been designed to work.
The outcomes are well defined in the docs comparison operators and comparison tables.
A == comparison between an array (your first two queries) and a string always results in false.
In a == comparison between a number and a string (your third query) the string is converted to a number and then a numeric comparison made. In the case of 0=='foo' the string 'foo' evaluates numerically to 0 and the test becomes 0==0 and returns true. If the string had been 'numeric' e.g. "3" then the result in your case would be false (0 not equal to 3).
Whether the design is "correct" (whatever that may mean) is arguable. It is certainly not always immediately obvious. An illustrative example of the potential fury of the debate can be found in Bug#54547 where the devs argue strongly that the design is rooted in php's history as a web language where everything is a string and should be left alone, and others argue php "violates the principle of least surprise".
To avoid uncertainty use === wherever possible, with the added benefit of potentially showing up assumptions in your code that may not be valid.
As someone has already said, the PHP automatic casting rules can be quite tricky, and it is worth using === unless you know both sides will be of the same type. However I believe I can explain this one:
""==[] (returns false)
The initial string "" indicates the comparison will be a string one, and thus [] is cast to a string. When that happens, the right hand side of the comparison will be set to the word Array. You are therefore doing this comparison:
"" == "Array" (returns false)
and thus false is the correct result.
Edit: a helpful comment below casts doubt on my answer via this live code example. I should be interested to see what other answers are supplied.

Strange variable assignment

I was studying some code I found on the web recently, and came across this php syntax:
<?php $framecharset && $frame['charset'] = $framecharset; ?>
Can someone explain what is going on in this line of code?
What variable(s) are being assigned what value(s), and what is the purpose of the && operator, in that location of the statement?
Thanks!
Pat
Ah, I just wrote a blog post about this idiom in javascript:
http://www.mcphersonindustries.com/
Basically it's testing to see that $framecharset exists, and then tries to assign it to $frame['charset'] if it is non-null.
The way it works is that interpreters are lazy. Both sides of an && statement need to be true to continue. When it encounters a false value followed by &&, it stops. It doesn't continue evaluating (so in this case the assignment won't occur if $framecharset is false or null).
Some people will even put the more "expensive" half of a boolean expression after the &&, so that if the first condition isn't true, then the expensive bit won't ever be processed. It's arguable how much this actually might save, but it uses the same principle.
&& in PHP is short-circuited, which means the RHS will not be evaluated if the LHS evaluates to be false, because the result will always be false.
Your code:
$framecharset && $frame['charset'] = $framecharset;
is equivalent to :
if($framecharset) {
$frame['charset'] = $framecharset;
}
Which assigns the value of $framecharset as value to the array key charset only if the value evaluates to be true and in PHP
All strings are true except for two: a string containing nothing at all and a string containing only the character 0

Categories