PHP IF-ELSE STAMENT - php

Code:
<?php
$a = 200;
$b = 300;
if ($a > $b + $b != 3)
print "Correct";
else
print "Incorrect";
?>
output is: Correct
Can someone help me understand why the output became "Correct"?

To understand what is happening here, you need to look at the list of operator precendence to see what is being evaluated first. It's not left to right. The order of the operators in your if statement are as follows:
+ - ++ -- ~ (int) (float) (string) (array) (object) (bool) # - arithmetic (unary + and -), increment/decrement, bitwise, type casting and error control
< <= > >= - associative comparison
== != === !== <> <=> - non associative comparison
So in essence, your if statement breaks down to this:
(($a > ($b + $b)) != 3)
With your values becomes
((200 > (300 + 300)) != 3)
((200 > 600) != 3)
(false != 3)
So of course, false is not 3, and makes your if statement correct. If you want to evaluation 200 is greater than 300 AND 300 is not 3, then you need the logical AND operator, or &&, which would be
($a > $b && $b != 3)
which would print Incorrect

Related

PHP multiple OR logical operators in one IF statement

I have a question about IF statements with multiple logical OR operators.
If we let:
$x=1;
A. I typical would write a IF statement comparing two items like this:
if($x == 1 || $x == 2) echo 'good';
else echo 'bad';
B. But, is this a valid IF statement? If not, why? (because it seems to work)
if($x == (1 || 2)) echo 'good';
else echo 'bad';
C. I typical would write a third comparison like this:
if($x == 1 || $x == 2 || $x == 3) echo 'good';
else echo 'bad';
D. What about this, following suit with B, above? (it does not seem to work)
if($x == (1 || 2 || 3)) echo 'good';
else echo 'bad';
The example in B, above works, but not the example in D. Why?
I cannot find any PHP documentation as to why.
Here is what happens for every version:
A. $x == 1 || $x == 2
PHP will compare $x with the value 1, this is true so it can short-circuit the if and echo 'good'.
B. $x == (1 || 2)
PHP will evaluate 1 || 2 because parentheses indicate the priority, as the result should be a boolean expression it will cast 1 to a boolean which evaluates to true so the expression becomes $x == true.
Now PHP will evaluate this expression. First it will cast both types to the same, according to the documentation, it will "Convert both sides to bool". So, same as above, as $x is 1 it will be cast to true and then the expression becomes true == true which is true.
C. $x == 1 || $x == 2 || $x == 3
It is the same as A.
D. $x == (1 || 2 || 3)
It is quite the same as B.
And, for the record 1 == (1 || 2 || 3) evaluates to true.

PHP while loop with 'or' condition always stops at higher value

I have a while loop with 2 conditions separated by 'or':
while (($i <= 8) || ($x <= 5)){
$i++;
$x++;
}
I want the loop to end when the lowest number is reached - in the above case 5. However, the above stops when the first, higher condition is met and it loops 8 times.
This still occurs when I swap the values, eg:
while (($i <= 5) || ($x <= 8))
The loop will still ignore <= 5 and loop through 8 times.
Would anyone know how I can fix this to have the loop cycle stop at the lower number?
It's doing what you have written. Use && instead of || and it will stop as soon as one of the conditions is no longer true.
The loop will execute as long as the expression inside while(expression) is true. In this case, your expression is $i <= 8 || $ x<=5 wich translates into:
$i is less or equal than 8 OR $i is less or queal than 5.
From php documentation:
$a || $b is TRUE if either $a or $b is TRUE.
If you want the smallest number, then you want both conditions to be true to continue the loop, so you use AND, which documentation is:
$a && $b is TRUE if both $a and $b are TRUE
So your code should be:
while (($i <= 8) && ($x <= 5)){
$i++;
$x++;
}
You can also use the keywords andand or, but be careful, because they have different operator precedence, in particular, they have less precedence:
http://php.net/manual/en/language.operators.precedence.php
Use and instead of or
while (($i <= 8) && ($x <= 5)){
}
If you use or it needs only one of its condition to be true for foing inside the loop. And will ensure that both of the condition should be true. So it will exit the loop when any one of the condition becomes false
You should use 'and' operation.
while($x<5 && $y<8) {//Your code here}
I suggest reading about this logic operators, these operators are basic in development.

Evaluate multiple conditions stored as a string

I have a few strings stored in a database which contain specific rules which must be met. The rules are like this:
>25
>25 and < 82
even and > 100
even and > 10 or odd and < 21
Given a number and a string, what is the best way to evaluate it in PHP?
eg. Given the number 3 and the string "even and > 10 or odd and < 21" this would evaluate to TRUE
Thanks
Mitch
As mentioned in the comments, the solution to this can be very simple or very complex.
I've thrown together a function that will work with the examples you've given:
function ruleToExpression($rule) {
$pattern = '/^( +(and|or) +(even|odd|[<>]=? *[0-9]+))+$/';
if (!preg_match($pattern, ' and ' . $rule)) {
throw new Exception('Invalid expression');
}
$find = array('even', 'odd', 'and', 'or');
$replace = array('%2==0', '%2==1', ') && ($x', ')) || (($x');
return '(($x' . str_replace($find, $replace, $rule) . '))';
}
function evaluateExpr($expr, $val) {
$x = $val;
return eval("return ({$expr});");
}
This supports multiple clauses separated by and and or, with no parentheses and the and always being evaluated first. Each clause can be even, odd, or a comparison to a number, allowing >, <, >=, and <= comparisons.
It works by comparing the entire rule against a regular expression pattern to ensure its syntax is valid and supported. If it passes that test, then the string replacements that follow will successfully convert it to an executable expression hard-coded against the variable $x.
As an example:
ruleToExpression('>25');
// (($x>25))
ruleToExpression('>25 and < 82');
// (($x>25 ) && ($x < 82))
ruleToExpression('even and > 100');
// (($x%2==0 ) && ($x > 100))
ruleToExpression('even and > 10 or odd and < 21');
// (($x%2==0 ) && ($x > 10 )) || (($x %2==1 ) && ($x < 21))
evaluateExpr(ruleToExpression('even and >25'), 31);
// false
evaluateExpr(ruleToExpression('even and >25'), 32);
// true
evaluateExpr(ruleToExpression('even and > 10 or odd and < 21'), 3);
// true
Why don't you translate the string even to maths? If you use mods you can write it like that $number % 2 == 0. In that case, your example will be:
if(($number % 2 == 0 && $number > 10 ) || ($number % 2 != 0 && $number < 21)){
//Then it is true!
}

comparing arrays in PHP - interesting behaviour

The first example:
$x = array("a" => 1, "b" => 2);
$y = array("b" => 1, "a" => 2);
$xLessY = ($x < $y);
$xGreaterY = ($x > $y);
var_dump($xLessY, $xGreaterY);
Result: $xLessY = true, $xGreaterY = true
The second example:
$x = array("a" => 2, "b" => 1);
$y = array("b" => 2, "a" => 1);
$xLessY = ($x < $y);
$xGreaterY = ($x > $y);
var_dump($xLessY, $xGreaterY);
Result: $xLessY = false, $xGreaterY = false
According to documentation on http://docs.php.net/manual/en/language.operators.comparison.php:
if key from operand 1 is not found in
operand 2 then arrays are
uncomparable, otherwise - compare
value by value
In our case each key from array $x is present in array $y, so $x and $y are comparable.
See also the example from documentation:
// Arrays are compared like this with standard comparison operators
function standard_array_compare($op1, $op2)
{
if (count($op1) < count($op2)) {
return -1; // $op1 < $op2
} elseif (count($op1) > count($op2)) {
return 1; // $op1 > $op2
}
foreach ($op1 as $key => $val) {
if (!array_key_exists($key, $op2)) {
return null; // uncomparable
} elseif ($val < $op2[$key]) {
return -1;
} elseif ($val > $op2[$key]) {
return 1;
}
}
return 0; // $op1 == $op2
}
This behaviour is really strange: $x is less than $y and at the same time $x is greater than $y (the first example) and two arrays are comparable.
I think this is because php always compares starting from the one definite side of sign '<'. I mean: for ($x < $y) php takes $x as operand 1, for ($x > $y) it takes $y as operand 1. Although I didn't find anything about this behaviour in documentation.
What are your thoughts on this?
Your assumption is correct. The > operator is parsed as
| expr '>' expr { zend_do_binary_op(ZEND_IS_SMALLER, &$$, &$3, &$1 TSRMLS_CC); }
This basically says, X > Y is equivalent to not X < Y, which is of course wrong when the comparison is not commutative. Consider reporting this on bugs.php.net.
I wouldn't say the bug is in $x > $y being substituted for $y < $x.
Sure, if you implemented $x > $y in a way that the arguments did not exchange positions when passed to the comparison function, you would solve this particular problem. But you get another in return.
Right now you have:
$x < $y <=> cmp($x, $y) == -1
$x > $y <=> cmp($y, $x) == -1
Because the first key of the first argument is always compared first, both conditions are true if reset($x) < $y[key($x)] and reset($y) < $x[key($y)].
But consider another implementation, which would solve this problem:
$x < $y <=> cmp($x, $y) == -1
$x > $y <=> cmp($x, $y) == +1
Now < and > are consistent when the order of the operands is fixed, but we now get weird behavior when we swap the operands because we could still have cmp($x, $y) == -1 and cmp($y, $x) == -1, which would mean $x < $y and $y < $x would both be true.
In sum, the only solution would be to fix the comparison function so that its behavior was antisymmetric, i.e. so that cmp($x, $y) == - cmp($y, $x), at least within a set of elements that are claimed to be comparable.
I may be wrong but I don't think you can compare arrays that way. I always assumed one can check for equality or inequality, but not compare quantities with < and >.
The man page on array operators seems to confirm this.

nested php ternary trouble: ternary output != if - else [duplicate]

This question already has answers here:
Stacking Multiple Ternary Operators in PHP
(11 answers)
Closed 2 years ago.
I am fairly capable at using the PHP ternary operator. However I have hit a roadblock at trying to figure out why the code below does not match the if-else equivalent structure. The test was run three times on different numbers. The output for each structure is below the code.
Ternary:
$decimal_places = ($max <= 1) ? 2 : ($max > 3) ? 0 : 1;
Ternary Output:
max: -100000 decimal: 0
max: 0.48 decimal: 0
max: 0.15 decimal: 0
If-Else
if($max <= 1)
$decimal_places = 2;
elseif($max > 3)
$decimal_places = 0;
else
$decimal_places = 1;
If-Else Output:
max: -100000 decimal: 2
max: 0.48 decimal: 2
max: 0.15 decimal: 2
Can anyone please tell me why the these two control stuctures do not output the same data?
Your right-hand-side ternary expression needs to be wrapped in parentheses so it'll be evaluated by itself as a single expression:
$decimal_places = ($max <= 1) ? 2 : (($max > 3) ? 0 : 1);
// Another way of looking at it
$decimal_places = ($max <= 1)
? 2
: (($max > 3) ? 0 : 1);
Otherwise your ternary expression is evaluated from left to right, resulting in:
$decimal_places = (($max <= 1) ? 2 : ($max > 3)) ? 0 : 1;
// Another way of looking at it
$decimal_places = (($max <= 1) ? 2 : ($max > 3))
? 0
: 1;
Which, translated to if-else, becomes this:
if ($max <= 1)
$cond = 2;
else
$cond = ($max > 3);
if ($cond)
$decimal_places = 0;
else
$decimal_places = 1;
Therefore $decimal_places ends up as 0 for all values of $max except 2, in which case it evaluates to 1.
The code is executed as
$decimal_places = (($max <= 1) ? 2 : ($max > 3)) ? 0 : 1;
so you'll never get 2 and 1 only when 1 < $max <=3. This is because the conditional operator is left-associative. Solution: Place parentheses to make sure the order you want is coded:
$decimal_places = ($max <= 1) ? 2 : (($max > 3) ? 0 : 1);
Just put the parenthesis and you would be fine, like this:
$decimal_places = ($max <= 1) ? 2 : (($max > 3) ? 0 : 1);
As others pointed out, use paranthesis.
However, if you actually want to make it readable, what about this:
$decimal_places =
($max <= 1) ? 2 : (
($max > 3) ? 0 : (
1
));
This still looks super awkward, but this awkwardness has a regular shape, so it's easier to live with.
$drink = 'wine';
return
($drink === 'wine') ? 'vinyard' : (
($drink === 'beer') ? 'brewery' : (
($drink === 'juice') ? 'apple tree' : (
($drink === 'coffee') ? 'coffeebeans' : (
'other'
))));
You could of course omit the last pair of brackets, but that would make it less regular-looking.

Categories