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.
Related
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.
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've perused the questions on ternary operators vs. if/else structures, and while I understand that under normal circumstances there is no performance loss/gain in using ternary operators over if/else structures, I've not seen any mention of this situation. Language specific to PHP (but any language agnostic details are welcome) does the interpreter reassign values in situations like this:
$foo = 'bar'
$foo = strlen($foo) > 3 ? substr($foo, 0, 3) : $foo;
Since this would evaluate to $foo = $foo; is this inefficient, or does the interpreter simply overlook/discard this evaluation?
On a side note, what about:
!defined('SECURE') ? exit : null;
I don't know if your first example is inefficient, but it sure is pointless. I still think an if statement is clearer:
$foo = 'bar';
if (strlen($foo) > 3)
$foo = substr($foo, 0, 3);
And while the following works, it makes no sense to place null at the end because a ternary operator is meant to be used to evaluate expressions/values, but here null does nothing other than to prevent a parse error:
!defined('SECURE') ? exit : null;
More commonly, you would see this, an example of boolean short-circuiting (or exit doesn't execute if SECURE is not defined, because the or conditional expression evaluates to true automatically once at least one condition is found to be true):
defined('SECURE') or exit;
The point I'm trying to make is this: don't use ternary conditional expressions just because you can.
In this cases, I use the form presented by BoltClock:
if (strlen($foo) > 3) {
$foo = substr($foo, 0, 3);
}
PHP does not implement something more simple to work in this cases, yet :/
The topic that using a ternary here is not optimal has already been covered above. I'm going to address your question about whether it will reassign the value:
This depends on what you call "reassigning". PHP does not optimize, so the $foo = $foo will be evaluated. On the other hand this will not cause PHP to copy the value of $foo to a new chunk of memory. Probably PHP will just increase the refcount on $foo and then immediately decrease it (though I'm not sure about the exact implementation details of self-assignment). So, even though PHP will execute the statement, it won't affect performance (unless you choose to write $foo = $foo seven million times in your code).
There is always short-circuiting, although as #BoltClock said, an if statement is probably more readable in my opinion, and opens the door to else if and else conditions as well.
strlen($foo) > 3 && $foo = substr($foo, 0, 3);
The latter statement will only be executed if the former evaluates to TRUE.
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.