isset and != in the same if clause - php

In my script a particular array element (say, $foo['bar']) can take different values, or no value at all. A particular action is triggered if the value of $foo['bar'] is not equal to, say, 42. The following code
if (!isset($foo['bar']) || ($foo['bar'] != '42')) action()
is not ideal, because php issues a warning about when $foo['bar'] is not set.
Question: is there an elegant way to test for such condition?

This code:
if (!isset($foo['bar']) || $foo['bar'] != 42) {
}
Because of short-circuiting logic will actually not issue any warnings, because it skips at the first truthy condition, in this case that happens if $foo['bar'] is not defined.
This can also be seen from the opcodes that the compiler generates for your code:
compiled vars: !0 = $foo
line # * op fetch ext return operands
------------------------------------------------------------------------------
3 0 > ZEND_ISSET_ISEMPTY_DIM_OBJ 1 ~0 !0, 'bar'
1 BOOL_NOT ~1 ~0
2 > JMPNZ_EX ~1 ~1, ->6
3 > FETCH_DIM_R $2 !0, 'bar'
4 IS_NOT_EQUAL ~3 $2, 42
5 BOOL ~1 ~3
6 > > JMPZ ~1, ->8
4 7 > > JMP ->8
8 > > RETURN 1
The below opcode is important:
2 > JMPNZ_EX ~1 ~1, ->6
The inverted outcome of isset($foo['bar']) gets checked and if truthy the code jumps over the next few statements that actually inspect the value of $foo['bar'], thereby avoiding any notices.
This also means that if you would reverse the two operands of || you will get a notice and the second operand is mostly useless anyway.
Because values like 0, false, [], etc. are also not equal to 42 you can use empty() as well:
if (empty($foo['bar']) || $foo['bar'] != 42) {
}
This arguably makes the code easier to read.

Can be in this way
$bar = isset($foo['bar']) ? $foo['bar'] : NULL;
There you don't get warning and you are setting the variable.
Then you do the check
if($bar != 42 && !empty($bar)){
//do something
}
Read Ternary Operator
The expression (expr1) ? (expr2) : (expr3) evaluates to expr2 if expr1 evaluates to TRUE, and expr3 if expr1 evaluates to FALSE.

I think this is what you want:
if (!(isset($foo['bar']) && ($foo['bar'] = '42'))) action();

For PHP 5.3+ you can use optimitzed version of Emilio Gort answer:
$bar = isset($foo['bar']) ?: '';
if ($bar != 42) action();

Related

Is it more expensive to set a variable twice or once but inside an else block?

Setting a variable twice
$var = 2;
if ($someThing) {
$var = 1;
}
VS
Using an else
if ($someThing) {
$var = 1;
}
else {
$var = 2;
}
I know that$someThing will get evaluated in both cases. $var Is also going to be set in both cases. In the former it's set once then 50/50 chance to get set again. The later it's set only once, but there's an else block.
I was just curious if anyone has done any sort of testing with something similar. I know this is really micro-optimizing, but just a random thought that I had.
You can look at the opcode steps for each option using the Vulcan Logic Dump
Option #1
compiled vars: !0 = $var, !1 = $someThing
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > ASSIGN !0, 2
4 1 > JMPZ !1, ->3
5 2 > ASSIGN !0, 1
3 > > RETURN 1
Option #2
compiled vars: !0 = $someThing, !1 = $var
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > > JMPZ !0, ->3
4 1 > ASSIGN !1, 1
2 > JMP ->4
7 3 > ASSIGN !1, 2
4 > > RETURN 1
and also using the Ternary operator
compiled vars: !0 = $var, !1 = $someThing
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > > JMPZ !1, ->3
1 > QM_ASSIGN ~2 1
2 > JMP ->4
3 > QM_ASSIGN ~2 2
4 > ASSIGN !0, ~2
5 > RETURN 1
EDIT
As Barmar points out, not all methods execute all the steps, because there are jumps here, and not all steps have an equal processing cost either
It's not about chance whether $someThing is fulfilled, but about the effort the machine has to make. Let's see:
$var = 2;
if ($someThing) {
$var = 1;
}
means min. 1 assignment and 1 check and max. 2 assignments and 1 check.
if ($someThing) {
$var = 1;
}
else {
$var = 2;
}
means min. 1 assignment and 1 check and max. 1 assignment and 1 check.
The else is optimal.
Note: If $someThing depends on $var outside this piece of code and it is called repeatedly and want to be absolutely sure that your code is optimal you'll have to do an amotized cost analysis which isn't too trivial.
You have to imagine it in assembly, which can differ based on architectures.
Here's some basic pseudocode:
write $var 2
bne $something x
write $var 1
x:
or
bne $something x
write $var 1
jmp y:
x:
write $var 2
y:
The first one has an extra write operation sometimes. The second one has an extra jump instruction sometimes. I would think that the jump instruction would be faster, and branch prediction would allow it to be optimised further under the hood, so I'd go for the second option.

What is the precidency and associtivity for increment operator and assignment operator for the block of code

What is the precidency and associtivity for increment operator and assignment operator for the block of code
$a=array(1,2,3);
$b=array(4,5,6);
$c=1;
$a[$c++]=$b[$c++];
print_r($a);
As per the execution it outputs
Array
(
[0] => 1
[1] => 6
[2] => 3
)
But I am not able to understand how array $a index 1 holds the value of array $b index 2 value. Can anybody explain the scenario how the execution happens?
PHP is (once again) different from other languages in that the left part of an assignment evaluates first. Simple proof:
$a[print 1] = $b[print 2]; // what does this print?
According to http://3v4l.org/, this code:
$a = array(); $b = array(); $c = 1;
$a[$c++]=$b[$c++];
generated following opcodes:
compiled vars: !0 = $a, !1 = $b, !2 = $c
line # * op fetch ext return operands
---------------------------------------------------------------------------------
2 0 > INIT_ARRAY ~0
1 ASSIGN !0, ~0
2 INIT_ARRAY ~2
3 ASSIGN !1, ~2
4 ASSIGN !2, 1
3 5 POST_INC ~5 !2
6 POST_INC ~7 !2
7 FETCH_DIM_R $8 !1, ~7
8 ASSIGN_DIM !0, ~5
9 OP_DATA $8, $9
10 > RETURN 1
The opcode 5 is the left $c++, and the opcode 6 is the right $c++. So the final assignment (opcode 8) is evaluated as
$a[1] = $b[2];
which results in (1,6,3).
The ++ post increment operator first returns the value and afterwards (post) increments the value. I.e. $c++ returns the value of $c, then increments $c.
It is then obviously executing like this:
$a[$c++] =
Here the value of $c++ is taken as 1, but $c is then post-incremented to 2.
$b[$c++]
Here the value of $c++ is taken as 2, and then $c is post-incremented to 3 (which nobody cares about anymore though).
So the expression is equivalent to:
$a[1] = $b[2];
For contrast, the pre-increment operator ++$var first increments the value, then returns the new incremented value. So $a[++$c] = $b[++$c] would result in a Undefined offset 3 in $b error.
It's called undefined order of evalution.
Operator precedence and associativity only determine how expressions
are grouped, they do not specify an order of evaluation. PHP does not
(in the general case) specify in which order an expression is
evaluated and code that assumes a specific order of evaluation should
be avoided, because the behavior can change between versions of PHP or
depending on the surrounding code.
http://php.net/manual/en/language.operators.precedence.php#example-130
But current behaviour have never changed: http://3v4l.org/b1Y1X

Why does this conditional statement not work?

I have this function in PHP to check if a number is 1 or 0, and if it isn't to die no access. This is for a lightweight security system implemented in one of my games to help prevent most cheating.
$number = 1;
if ($number<>0 || $number<>1){
die("nope");
}
However, when I run this code above, nope is echoed. Why?
The <> comparison operator is the same as != (not equal). The || is an OR comparison operator. In the conditional statement above if either expression is not true, the code block will execute. since 1 != 0, the code block will execute.
You are checking if $number is greater/less than 0 OR greater/less than 1. Since 1 is greater than 0 the first condition is true and the statement is true. So you get the message 'nope'.
Change it to this:
if ($number <> 0 && $number <> 1){
Your code always pass, it checks if $number is NOT one or is NOT zero - try proper solution:
$number=1;
if (!($number==0 || $number==1)){
die("nope");
}
your first condition $number<>0 is true. <> means not equal to(!=). 1 != 0 is true.
so it is always inside if condition.
Your condition $number<>0 || $number<>1 will be true when $number is 1 because 1 is not equal to 0. Since you are using ||, it will short-circuit since true || <anything> is true.
You want to use && here instead. To check whether $number is not equal to either 0 or 1.
$number=1;
if ($number<>0 && $number<>1){
die("nope");
}
Following De Morgan's laws, you can also do:
$number=1;
if (!($number==0 || $number==1)){
die("nope");
}

Difference between & and && in PHP

I am confused with & and &&. I have two PHP books. One says that they are same, but the another says they are different. I thought they are same as well.
Aren't they same?
& is bitwise AND. See Bitwise Operators. Assuming you do 14 & 7:
14 = 1110
7 = 0111
---------
14 & 7 = 0110 = 6
&& is logical AND. See Logical Operators. Consider this truth table:
$a $b $a && $b
false false false
false true false
true false false
true true true
The other answers are correct, but incomplete. A key feature of logical AND is that it short-circuits, meaning the second operand is only evaluated if necessary. The PHP manual gives the following example to illustrate:
$a = (false && foo());
foo will never be called, since the result is known after evaluating false. On the other hand with
$a = (false & foo());
foo will be called (also, the result is 0 rather than false).
Matthew's answer about how Logical And && operator is the biggest difference; logical comparison will stop when it will find something that breaks the chain. In addition, one more big difference it the result type/value.
tl;dr
By using the Logical And &&, it will always return a Boolean type/value, true or false.
false & 1 // int(0)
false && 1 // bool(false)
It is important to use Boolean type/values when returning a function with a logical result, because someone can use the Identical comparison operator === to compare the results (which is high likely to happen) and it will fail if you use something like this:
(false & 1) === false // bool(false)
(true & true) === true // bool(false)
Never use Bitwise And & when you need to make a logical comparison and especially when returning values from functions with logical results. Instead use the Logical And &&:
(false && 1) === false // bool(true)
(true && true) === true // bool(true)
When comparing characters, Logical And && will always result to true, even with NUL character, unless if it's converted to an integer:
'A' && 'B' // bool(true)
'A' && 0 // bool(false)
'A' && '\0' // bool(true)
'A' && (int)'\0' // bool(false)
If you use the Bitwise And & with characters, it will result the character corresponding to the Bitwise And operation between those two characters:
'A' & 'B' // string(1) "#"
01000001 // ASCII 'A'
&
01000010 // ASCII 'B'
=
01000000 // ASCII '#'
Beware the usage of the Bitwise And & when using with types other than Integers and Characters (which are special kind of integers). For example, if you use it with real numbers float/double, then it can result to 0 even if both operands are NOT 0:
1.0 & 1.0 // int(1)
2.0 & 1.0 // int(0)
1.0 && 1.0 // bool(true)
2.0 && 1.0 // bool(true)
In addition, if we go at assembly instructions level, we can see that difference and how the compiler manages to handle so the Logical And && uses cmp <var>, 0 to compare and does not continue executing if one operand fails; Bitwise And uses and <var1>, <var2> to make a bitwise result and then test if it's of 0 value. I know this question is tagged for php and php behavior may be different than c, but I'll use a small c program to demonstrate how compiler behaves when using Logical and Bitwise And.
Let's assume we have a program in c that uses both Bitwise and Logical And:
int a = 0;
int b = 1;
int c = 2;
if (a & b)
c = 3;
if (a && b)
c = 4;
The compiler will generate the following assembly opcodes (W32Dasm result for x86; I have changed the memory addresses with <variable> names for simplicity and to be more understandable):
:0229 mov <a>, 0
:0230 mov <b>, 1
:0237 mov <c>, 2
// if (a & b) begins
:023E mov eax, <a>
:0241 and eax, <b> // a bitwise and b, result stored to eax
:0244 test eax, eax // test eax and set ZeroFlag if equals to 0
:0246 je 024F // >--- Jump if ZeroFlag is set
:0248 mov <c>, 3 // | or set c = 3
// if (a && b) begins |
:024F cmp <a>, 0 // <--- compare a to 0 and sets ZeroFlag if difference is 0
:0253 je 0262 // >--- Jump if ZeroFlag is set (a == 0)
:0255 cmp <b>, 0 // | compare b to 0 and sets ZeroFlag if differemce is 0
:0259 je 0262 // | >--- Jump if ZeroFlag is set (b == 0)
:025B mov <c>, 4 // | | or set c = 4
:0262 <program continues> // <--- <---
The compiler not only uses different instructions to compare between the Logical and Bitwaise And, but at the line :0253 in if (a && b) logical comparison, we see that if a == 0 then it jumps and does not check for the rest operands.
So, I disagree to animuson's comment:
They are both the same thing, they're just used for two different
things to accomplish the same task. – animuson Mar 4 '10 at 1:42
They are not the same thing and both are/(should be) used for specific tasks depending on the programs' logic/flow.
AND operation:
& -> will do the bitwise AND operation , it just doing operation based on
the bit values.
&& -> It will do logical AND operation. It is just the check the values is
true or false. Based on the boolean value , it will evaluation the
expression
As the others are saying, a single & is bit-wise. It basically converts the left-hand value into its bits representation, and the right hand side into bits representation as well, then performs logical AND between them and outputs the result.
Double && is either true or false, (in some languages 0 or 1) if both left and right side are true (or non-zero).
I'd also add that this is not just in PHP. It is like that in many many other languages as well, like C, Java, Ruby, etc.
&& is & performed on operands reduced to either 1 or 0.
(In other words, && is a bitwise operator under the caveat that it changes its operands. That is, logical operations are a subset of bitwise operations.)

What is the difference between the | and || operators?

| and || - what is the difference between these two operators in PHP?
| is a bitwise or, || is a boolean or.
Meaning
| is binary operator, it will binary OR the bits of both the lefthand and righthand values.
|| is a boolean operator, it will short circuit when it encounters 'true' (any non-zero value, this includes non-empty arrays).
Examples
print_r(1 | 2) // 3
print_r(1 || 2) // 1
When used with functions:
function numberOf($val) {
echo "$val, ";
return $val;
}
echo numberOf(1) | numberOf(2); // Will print 1, 2, 3
echo numberOf(1) || numberOf(2); // Will print 1, 1
Just like the & and && operator, the double Operator is a "short-circuit" operator.
For example:
if(condition1 || condition2 || condition3)
If condition1 is true, condition 2 and 3 will NOT be checked.
if(condition1 | condition2 | condition3)
This will check conditions 2 and 3, even if 1 is already true. As your conditions can be quite expensive functions, you can get a good
performance boost by using them.
There is one big caveat, NullReferences or similar problems. For example:
if(class != null && class.someVar < 20)
If class is null, the if-statement will stop after "class != null" is false. If you only use &, it will try to check class.someVar and you get a
nice NullReferenceException. With the Or-Operator that may not be that much of a trap as it's unlikely that you trigger something bad,
but it's something to keep in mind.
No one ever uses the single & or | operators though, unless you have a design where each condition is a function that HAS the be
executed. Sounds like a design smell, but sometimes (rarely) it's a clean way to do stuff. The & operator does "run these 3 functions,
and if one of them returns false, execute the else block", while the | does "only run the else block if none return false" - can be useful,
but as said, often it's a design smell.
| operates on the bits of a variable: 2 | 4 = 6
|| operates on The Boolean value of a variable: 2 || 4 = TRUE
| -> binary operator || -> Boolean operator or -> also a Boolean
operator with lower precedence
$x = false | true; //will set $x to an integer
$x = false || true; //will set $x to true
$x = false or true; //will set $x to false exactly the same that:
($x = false) || true;

Categories