Pretty sure there's a simple answer to this but difficult to search on because of the vague terms used.
I'm using shorthand if statements and want to do more than one action when it returns true, what does the syntax look like?
For example, logically thinking I tried something like:
<?php
$var = "whatever";
(isset($var) ? $var2=$var; $var3=$var : $error="fubar");
?>
Obviously this stops with unexpected ; but hopefully you get the idea of what I'm trying to accomplish.
So sorry if this is a duplicate question, I swear I searched for it. :)
Thanks!
EDIT
I understand that whether or not shorthand is appropriate for this situation should be questioned. But still, can it be done, is the question.
Yes it's possible by using && between each assignment:
(isset($var) ? ($var2=$var) && ($var3=$var) : $error="fubar");
In the above code, if $var is set, $var2 and $var3 will get the same value, otherwise the two variables will not be changed.
That said, it is not the most appropriate method. The ternary operator should be used for simple logic, when the logic starts to get complicated, ternary is most likely no longer the best option. Instead you should just use a simple if/else.
For this specific instance, you can do this:
In this specific instance you can use this:
$output = (isset($var)) ? $var2 = $var3 = $var : false;
Slightly better option for this specific test instance:
$error = (isset($var)) ? !(bool)($var2 = $var3 = $var) : true;
This will set $error to true IF $var is not set, and to false if $var is set, so you could follow this up with an if($error) block.
However, ternary probably isn't the best way to approach this...
For more complicated instances you'd need to use closures or, worse, predeclared functions:
$output = (isset($var)) ? setVars($var) : false;
function setVars($var) {
$var2 = $var3 = $var;
}
At this point, you're probably better off with if or switch statements.
As far as I know, it is not possible, and shouldn't be possible. (?:) is not, and should not be taken as a if, because it doesn't works the same way, and is not designed for it.
The ternary operator exist as a way to return a value depending of a condition, not as a "quick" if.
If you are using it without needing the return value, then you probably are using it wrong.
In this specific case, you should be using and if-else statement. It would also help making your code more readable.
Related
There are plenty of ways to do this. My question isn't "how do I test variables and assign variables". The question is how can I do this with the least amount of code possible and not repeat certain text.
It's common to need to read, validate and assign variables from GET or POST, I'm trying to find the most concise way to do it.
When I need a GET variable, I typically test it with both ISSET and EMPTY. Then I might do a further validation on the data type, and then finally assign it to a working variable. Like this for example:
if (isset($_GET['id']) && !empty($_GET['id'])) {
if (is_numeric($_GET['id'])) {
$var = $_GET['id'];
// code
}
}
I'm leaving out the various "else" conditions but you get the idea. The most obvious annoyance here is having to type $_GET['id'] 4 times. Another one is having to do all my code within a 2-level if block.
My question is, can I do all the tests and validations and assignments in a more DRY way? Something like this pseudocode:
if ($var = isset(!empty(is_numeric($_GET['id']))) {
// $var is now equal to $_GET['id'];
} else {
// failed all tests, $var is equal to false;
}
Assuming that the GET passes the three tests, $var would be assigned the actual value of the GET, rather than true/false.
Yes I can do this and NOT be DRY. Yes I can do this with a custom function. I'm just wondering if I can wrap it all up this way or not, in a small, concise, DRY, single statement. I've been playing with tertiary statements but still not perfect and DRY.
I'm doing with ternary operator like the following:
$var = empty($var) ? $default : $var;
What about:
$getVar = empty($_GET['var'])?null : $_GET['var'];
$var = (!is_null($getVar) && is_numeric($getVar))? $getVar : false;
DRYest I can get it.
(Sorry about the lack of formatting- am typing from a phone)
I cant seem to find any discussion about this.
In JavaScript to check if something exists, and use a default if it doesn't is like this:
var myvariable = mysetting || 3
In PHP from what I understand, the same thing can be done like this:
$myvariable = $mysetting ?: 3;
Am i completely off on this? I understand the implications of not using isset() and not_empty() and all that, but if I just want to know if the variable exists and is truthy otherwise use a default - this should work I think. Does this syntax have any hidden bad things about it?
Because it doesn't work. That code will still throw a notice Notice: Undefined variable: mysetting in C:\wamp\www\x.php on line, which might be visible to the user, depending on the PHP settings. Apart from that, it will work. If notices are suppressed, then the end result is correct.
So, to get around that, you can either use isset, which isn't really a function, but a language construct, and is specifically designed to do this check:
$myvariable = isset($mysetting)? $mysetting: 3;
Or you can suppress the notice using the # operator:
$myvariable = #$mysetting ?: 3;
For this specific case, maybe it's acceptable, but in general the use of # is frowned upon by many. Personally, I would rather use a couple more characters and make it feel less 'dirty', but it's a matter of opinion.
Another reason why people may not use it, is that it's relatively new (PHP 5.3). Not everyone might know of this new syntax or be comfortable with it. They have been used to isset for years, and old habits die hard.
Those statements are not equivalent. From what I have found the javascript is equivalent to:
if (!mysetting) {
myvariable = 3;
} else {
myvariable = mysetting;
}
Whereas the equivalent PHP statement using the ternary operator would be:
$mysetting = isset($myvariable) ? $myvariable : 3;
aka:
if( isset($myvariable) ) {
$mysetting = $myvariable;
} else {
$mysetting = 3;
}
The ternary operator is essentially a shorthand for and if/else statement, and the first operand is interpreted as a logical expression.
I've been thinking of using reference assignment as a shortcut for dealing with potentially undefined variables.
In other words, instead of:
$foo = isset($this->blah['something']['else']) ? $this->blah['something']['else'] : null;
if (!is_null($foo) && ...){
//do something with $foo
}
I could do this:
$foo = &$this->blah['something']['else'];
if (!is_null($foo) && ...){
//do something with $foo
}
Seems simpler, right? Because of the way PHP handles assignment by reference, I don't have to worry about $this->blah['something']['else'] being defined, because if it doesn't exist it will be created automatically and set to NULL.
Is this strategy frowned upon?
If you just want to test if a variable is set and not null, then you better test:
if (! empty($this->blah['something']['else'])) {...}
This way you avoid creating two references to a value that could not even exist.
In my opinion, every time you create a new reference to the same value, your code becomes harder to understand at a glance.
If you need zero as non-empty, then you better create a global function like this:
function eempty(& $var) {
return empty($var) && $var !== 0;
}
I personally think it could be more conventional, but assigning a referred value like that seems a bit redundant to me. I'd just stick with the more commonly used ternary operator in your situation. Often it's a lot clearer to understand. Of course, you should follow your personal semantics as close as possible.
I'm curious is there a way to write a shorthand setter in PHP. My primary quest when writing code is to make it as tight as possible and I think the following is kind of cumbersome:
$value = "Which array do I go in?";
if(true)
$arr_1[] = $value;
else
$arr_2[] = $value;
Is there a better way to write that? I tried to use the shorthand if:
(true)?$arr_1[]:$arr_2[] = "Which array do I go in?";
But that doesn't seem to work. Anyone have any cool tricks for this type of situation?
Thanks!
There is no shorthand for what you are trying to do. Also you should realize that making code "as tight as possible" often comes at the cost of readability.
EDIT: There is some ugly hacks to do what you want, but I would strongly recommend against. E.g.:
$GLOBALS[cond ? 'varname1' : 'varname2'] = $value;
Another hack would be:
$arr = ($cond ? &$arr_1 : &$arr_2);
$arr[] = 'Which array do I go in';
it's two lines but it doesn't require global and would work in a function. However for readability it is probably better to use an if statement. (Note: the & is making a reference to the variable, which is why this works). Another (which might make you understand HOW the ternary operator works) would be:
$cond ? $arr_1[] = $value : $arr_2[] = $value;
You see the ternary operator only evaluates (runs the code path) of the successful evaluation (on the right side of the ? if true, on the right side of : if false). However if you think this is faster than using 'if' you are wrong, your less 'tight' code will actually perform better.
Another option (e.g. if you can't/don't want to use globals).
${$cond?'arr_1':'arr_2'}[] = $value;
I want to set a variable to a value, but only if a condition is true.
Instead of doing the following:
if($myarray["foo"]==$bar){
$variablename=$myarray["foo"];
}
This can end up being quite long if the variable names are long, or perhaps it involves arrays, when it's quite simple what I want to do — set a value if a condition is true.
I would like to use the conditional operator, something like this:
$variablename=($myarray["foo"]=="bar")? $myarray["foo"]......
But this fails because I don't want the variable to be set at all if the statement is false.
Basically, what I'm trying to do is make the first example shorter. Perhaps the conditional operator is not the way though...
Does anyone have any suggestions?
It doesn't get much shorter than:
if($condition) $var = $value;
IMO, the best way to make your code sample shorter is:
if($myarray["foo"] == $bar)
$variablename = $myarray["foo"];
FYI, the name of the operator you're asking about isn't "the ternary operator", it's the conditional operator.
Since you ask, a way you could actually use the conditional operator to do what you're asking is:
$myarray['foo'] == $bar ? $variablename = $myarray['foo'] : null;
but that's somewhat horrifically ugly and very unmaintainable.
You could do this, but I wouldn't as it is pretty unreadable and stupid:
$myarray["foo"] == $bar ? $variablename = $myarray["foo"] : 0;
or
$myarray["foo"] == $bar && $variablename = $myarray["foo"];
Your right, ternary is not the way to go. It's there to handle the if and else part of the statement.
Just stick with the regular if statement.
if($myarray["foo"]==$bar) $variablename=$myarray["foo"];
The "problem" you have isn't really a problem. Your example code is very clear and maintainable. I would really say leave it like it is.
You -could- remove the braces, but that will have an impact on maintainability.
Your other alternative is to create a set_if_true(mixed array, string key, boolean conditional) wrapper function. It hides what is really happening but depending on your specific implementation it is a good option. (For instance a configuration type object, or caching backend)
Put != instead of == and ?: instead of just ?..
$variablename = ($myarray["foo"] != "bar") ?: $myarray["foo"];
is the same as
if($myarray["foo"] != "bar"){} else { $variablename = $myarray["foo"]; }
It might not be the smartest solution but it works. I like this one more
if($myarray["foo"] != "bar") {$variablename = $myarray["foo"]};
Set the variable to itself in the false case:
$variablename=($myarray["foo"]=="bar")? $myarray["foo"] : $variablename
You can put the original expression in the else part of the ternary operation, but if you want to guarantee single evaluation of the expression then you'll have to use a temporary variable and an if statement.
Ternary isn't the way, even though it can be written so that ternary works.
The reason is this: you're trying to use it in a way it's not intended, which will make your code awkward for other developers to read.