After checking some shorthand if's i got confused.
$num = 10;
return ($num>0)? 'banned' : 'free';
and
$num = 10;
return ($num>0 ? 'banned' : 'free');
are both equal or the first one is wrong?
Both of the case are true is their own state.
The first one
return ($num>0)? 'banned' : 'free';
is used when you need to compare two or more conditions as in
return ($num > 0 && $num <= 10) ? 'banned' : 'free'. ' model' ;
Here, ' model' is applied to only false condition.
This can be applied into the second expression as well.
The brackets in second expression defined as one expression. as in
return ($num > 0 ? 'banned' : 'free' ) . ' model' ;
Here, ' model' is concatenated to any of the result.
Its totally based on your priority of selecting the bracketss.
Related
I'm still getting used to ternary operators and I find it a helpful way of minimizing code. I can make sense out of it if it is simple like the example showed below (example 1)
Example 1
$OrderType = ($name == 'first' ? 'Fred' : ($name == 'last' ? 'Dabo' : 'RAND()'))
This can be read as: if $name is 'first' then use 'Fred' else if $name is 'last' then use 'Dabo' else use 'RAND()'
However I saw this (example 2) on another website and it doesn't make any sense to me.
Example 2
$score = 10;
$age = 20;
echo 'Taking into account your age and score, you are: ',($age > 10 ? ($score < 80 ? 'behind' : 'above average') : ($score < 50 ? 'behind' : 'above average')); // returns 'You are behind'
So can someone explain to me in simple language how this ternary operator will read?
In simple language, that ternary says, if $age > 10, consider 80 a good score, otherwise consider 50 a good score.
Rather than nesting ternaries, consider breaking out the nested logic into its own helper function. I find the following code much more understandable.
function adult_score($score) {
return $score > 80 ? "behind" : "above average";
}
function child_score($score) {
return $score < 50 ? "behind" : "above average";
}
$score = 10;
$age = 20;
echo $age > 10 ? adult_score($score) : child_score($score);
So, you understand a ternary, part before the ? is the if statement, part between ? and : is the "to do if truthy" and the part after : is the "to do if falsey". So if you took that ternary and wrapped the "if" part with an if statement and wrapped the "true" and "false" with curly braces and replaced the : with an else, you end up with this:
if($age > 10){
if($score < 80){
return 'behind';
} else {
return 'above average';
}
} else {
if($score < 50){
return 'behind';
} else {
return 'above average';
}
}
Like others have said though, it is ugly and hard to follow. Unless your goal was to make it hard for others to follow your code, then don't do this. Just please, don't. They are nice for one off if statements, but get confusing fast. Do yourself and any future readers of your code a favor.
This question already has answers here:
Reference Guide: What does this symbol mean in PHP? (PHP Syntax)
(24 answers)
Closed 8 years ago.
I am new to Laravel framework(i.e a framework driven from Symfony library) .I was looking at the code of Symfony and came across some short cuts that i think i can use to improve my ability to code neatly.
I want to know about the behavior of these operators? ( ?: etc)
1- $this->history = $history ?: new History();
//Does this mean create object of History class and store in $this->history?
2- $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
3- $this->followRedirects = -1 != $this->maxRedirects;
//Not sure how operators are behaving?i know this is something to do with regex but want to know the logic.
I would appreciate if somebody could post a link of tutorial about regex programming in php like above.
The first and the second use the ternary operator:
condition ? code_if_true : code_if_false
Note that code_if_true or code_if_false can be empty.
the third assigns to the variable the result of the test: -1 != $this->maxRedirects
So, true or false.
1) $this->history = $history ?: new History();
if $history has a value equivalent to false the history attribute is set to a new instance of the class History. If $history has a value equivalent to true, the history attribute is set to the $history value.
2) $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
if $maxRedirects is negative the maxRedirects attribute is set to -1, otherwise it is set to $maxRedirects.
3) $this->followRedirects = -1 != $this->maxRedirects;
if $this->maxRedirects is different from -1, $this->followRedirects is set to true, otherwise false.
The best way to understand it is to look at only one page:
http://php.net/manual/en/language.operators.comparison.php
I think that to work with Symfony you need be more experienced developer. Try to learn PHP first, then you can try to learn how to work with frameworks written on PHP. Also I think that before you will start to learn frameworks you should read some books about Design Patterns.
1) and 3) are known as a ternary. I.e.
echo $isFoo ? "Is foo" : "No foo for you!";
Will echo the "Is foo" if foo is true and "No foo for you!" otherwise.
Since PHP 5.3 you can omit the middle:
echo $fooLabel ?: "Default foo label";
This will show $fooLabel if it is true and "Default foo label" otherwise.
Finally 3)
$this->followRedirects = -1 != $this->maxRedirects;
This simply evaluates -1 != $this->maxRedirects. This will be true if maxRedirects is not equal to -1. The result is then stored in $this->followRedirects.
The if-else shorthand follows the following format:
<condition> ? <condition is met> : <condition is not met>
This:
$age = 20;
echo $age >= 21 ? 'Have a beer' : 'Too young! No beer for you!';
Is the same as this:
if($age >= 21){
echo 'Have a beer';
}else{
echo 'Too Young! No beer for you!';
}
Your example #1, since PHP 5.3, simply omits the first condition of the shorthand and executes new History() only if the condition is not met:
$this->history = $history ?: new History();
Note you can also omit the second condition if you'd like. Also, if the omitted portion of the shorthand is met, 1 is returned, since no other instruction is given.
I thinks it's best to illustrate how these operators work by example:
1)
$this->history = $history ?: new History();
Is equal to
if ($history) {
$this->history = $history;
} else {
$this->history = new History();
}
2)
$this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects;
Is equal to
if ($maxRedirects < 0) {
$this->maxRedirects = -1;
} else {
$this->maxRedirects = $maxRedirects;
}
3)
$this->followRedirects = -1 != $this->maxRedirects;
Is equal to
$this->followRedirects = (-1 != $this->maxRedirects);
Is equal to
if (-1 != $this->maxRedirects) {
$this->followRedirects = true;
} else {
$this->followRedirects = false;
}
NOTE: I am aware that this is not acceptable code, I am seeking to understand what the interpreter is doing, not advice on how else to achieve the same result!
I've since read up enough to realize that I can't and shouldn't be attempting to use |,|| or XOR in defining a switch caseāso please don't comment to the effect of "don't do that", I'm just trying to understand what the interpreter is doing with such statements and to understand the strangeness of the behavior. I'm using PHP 5.3.1.
This is what I was actually intending to do and am now using, please don't recommend code:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : -5; //angle from goal
break;
case 1:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
case 2:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -10; //miss penalty
break;
case 3:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : -10; //error penalty
break;
}
}
But got curious if I could do:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0 || 1:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15; //angle from goal
break;
case 2 || 3:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
}
}
and, perversely, this does run, but very slowly (like, seconds), and though of course it evaluates (0||1) not at all the way I'd intended (and indeed today was a lesson on the difference between bitwise and logical operators).
But more curious to me was the fact that I could do this, if very slowly and not with the results I'd wanted:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0 XOR 1:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15; //angle from goal
break;
case 2:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
case 3:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
}
}
But I could not do this:
for ($i=0; $i<count($this->header); $i++) {
switch($i) {
case 0 XOR 1:
$this->header[ $i ] = $this->header[ $i ] ? $this->header[ $i ] : 15; //angle from goal
break;
case 2 XOR 3:
$this->header[$i] = $this->header[$i] ? $this->header[$i] : -5; //miss penalty
break;
}
}
This was the only one of these terrible, terrible ideas that PHP wouldn't even evaluate.
My question is: why does evaluating these statements take so, so much longer, and why does the last example not run? I considered that PHP was interpreting 0 XOR 1 and comparing true and false, but I couldn't substitute those in and have it still evaluate. Anyone know what's happening here? Thanks!
UPDATE:
Comments requested a var_dump($this->header) (in case it isn't obvious, I truncated my initial switch statement from 7 cases to 4 just to avoid spamming lines of identical code, but, given that the var_dump() was requested, I chose to post the whole thing in case it revealed something I couldn't forsee!). Also, yes, it turns out I'd been using an associative array due to forgetting to have called array_values() before setting $this->header, in the second answer below, having made this error turns out to explain the duration of the switch statement, whilst the first answer and second answer together are great walkthroughs of the logic.
array(12) {
["theZone"]=>
NULL
["leftMiss"]=>
NULL
["rightMiss"]=>
NULL
["leftError"]=>
NULL
["rightError"]=>
NULL
["leftHit"]=>
NULL
["rightHit"]=>
NULL
["accuracy"]=>
string(5) "false"
["rt"]=>
string(4) "true"
["disease"]=>
string(3) "yes"
["bars"]=>
string(3) "yes"
["endMessage"]=>
NULL
}
case values have to be SINGLE values. You can't do 2 || 3, because that'll evaluate as
case (2 or 3) -> case TRUE
Similarly, if you were using && (and), you'd get
case (0 and 1) -> case FALSE
You can use 'fallthrough' behavior for the OR logic:
case 2:
case 3:
...code here ...
break;
XOR, you can't do. not with a simple case statement.
comment followup:
for ($i = 0; $i < 5; $i++) {
switch($i) {
case 0 xor 1: echo "0 xor 1: $i\n"; break;
case 2 xor 3: echo "2 xor 3: $i\n"; break;
}
}
will output
2x3: 0
0x1: 1
0x1: 2
0x1: 3
0x1: 4
and
php > var_dump(2 xor 3);
bool(false)
php > var_dump(0 xor 1);
bool(true)
Remember that switch cases evaluate the same ==. They're lazy comparisons, not checking types. So your 2 xor 3 is evaluated the same as if the case has been case false, which makes the $i=0 condition match.
Haha, it's quite funny, what you did there.
It's not the switch which gets you into performance troubles. It probably is your for-loop in combination with your switch.
I try to explain it with the second example given.
However, I just have to guess, and so I have to assume that your $this->header array looks like the following (this would be the only reason for your performance leak):
$this->header = array(
999 => 10, // the value is irrelevant, only the key (2) matters
998 => 15
);
Now lets play interpreter debugger.
set $i to 0
is $i<count($this->header)? yes, because header size is 2
is ($i == (0 || 1))? no, because (0 == (0 || 1)) equals (0 == true) equals (false == true) can never be true
is ($i == (2 || 3))? no, because (0 == (2 || 3)) equals (0 == true) equals (false == true) will never comply
next loop, increment $i (set $i to 1)
is ($i<count($this->header)? yes, because header size is 2
is ($i == (0 || 1))? yes, because (1 == (0 || 1)) equals (1 == true) equals (true == true)
go into case statement
set $this->header[1] to -5 (remember the index 1 does not exist so far in your array)
next loop, increment $i (set $i to 2)
is $i<count($this->header)? yes, because header size is 3 (remember? you just added a new index which incremented your header size)
is ($i == (0 || 1))? yes, because (2 == (0 || 1)) equals (2 == true equals (true == true)
go into case statement
set $this->header[2] to -5 (again index 2 did not exist so far)
next loop, increment $i (set $i to 3)
is $i<count($this->header)? yes, because header size is 4 (again, you just added a new index)
Now this will continue until the header size equals $i. In the example above this would happen after 998 iterations, because this would be the first time when there won't be a new index creation (the existing one - 998 - would simply be used), resulting in count($this->header) not changing.
In your first example, this will not happen. The header size will stop to change after the fourth iteration, because the case statement tries to compare integer values instead of booleans. As soon as it reaches index 5 it tries to compare to the values 1, 2, 3 and 4 and will not match a single one, resulting in no new index creation.
To fix the the performance issue, you should make sure that every key in your array exists and also change your for-loop as follows:
$size = count($this->header);
for($i=0; $i<$size); $i++) {...}
Of course this won't fix your logical problems. But since you asked for what is going on, this should be a good explanation, I guess.
var_dump()-ing your $this->header array before and after your loop should prove me right :)
===
Sorry for deleting and undeleting this answer. Just wanted to make sure it really behaves as explained. If you could provide me with a var_dump of your header array, it would be great.
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!
}
I am trying to convert the following code into a Ternary Operator, but it is not working and I am unsure why. I think my problem is that I do not know how to express the elseif operation in ternary format. From my understanding and elseif is performed the same way as an if operation by using the format : (condition) ? 'result'.
if ($i == 0) {
$top = '<div class="active item">';
} elseif ($i % 5 == 0) {
$top = '<div class="item">';
} else {
$top = '';
}
$top = ($i == 0) ? '<div class="active item">' : ($i % 5 == 0) ? '<div class="item">' : '';
$top = ($i == 0) ? '<div class="active item">' : (($i % 5 == 0) ? '<div class="item">' : '');
you need to add parenthesis' around the entire else block
The Ternary Operator doesn't support a true if... else if... else... operation; however, you can simulate the behavior by using the following technique
var name = (variable === 1) ? 'foo' : ((variable === 2) ? 'bar' : 'baz');
I personally don't care for this as I don't find it more readable or elegant. I typically prefer the switch statement.
switch (variable) {
case 1 : name = 'foo'; break;
case 2 : name = 'bar'; break;
default : name = 'bas'; break;
}
Too late probably to share some views, but nevertheless :)
Use if - else if - else for a limited number of evaluations. Personally I prefer to use if - else if - else when number of comparisons are less than 5.
Use switch-case where number of evaluations are more. Personally I prefer switch-case where cases are more than 5.
Use ternary where a single comparison is under consideration (or a single comparison when looping), or when a if-else compare is needed inside the "case" clause of a switch structure.
Using ternary is faster when comparing while looping over a very large data set.
IMHO Its finally the developer who decides the trade off equation between code readability and performance and that in turn decides what out of, ternary vs. if else-if else vs. switch-case, can be used in any particular situation.
//Use this format before reducing the expression to one liner
$var=4; //Change value to test
echo "Format result: ";
echo($var === 1) ? 'one' : //if NB.=> $varname = || echo || print || var_dump(ternary statement inside); can only be (placed at the start/wrapping) of the statement.
(($var === 2) ? 'two' : //elseif
(($var === 3) ? 'three' : //elseif
(($var === 4) ? 'four' : //elseif
'false' //else
))); //extra tip: closing brackets = totalnumber of conditions - 1
// Then echo($var === 1)?'one':(($var === 2)?'two':(($var === 3)?'three':(($var === 4)?'four':'false')));
echo "<br/>";
var_dump("Short result: ", ($var === 1)?'one':(($var === 2)?'two':(($var === 3)?'three':(($var === 4)?'four':'false'))) );