The simplest way of using the coalesce operator and function calls - php

I want to simplify my PHP code, and while I find the coalesce operator extremely useful, I don't know if / how I can use it when calling a function from an object.
For example,
$message = $error_msg ?? 'No error message';
Works, but:
$message = $exception->getMessage() ?? 'No error message';
Doesn't. I end up having to resort to:
$message = isset($exception) ? $exception->getMessage() : 'No error message';
Is there any way to make something like the second line of code work, or is the third example the only way to do it?
Apologies in advance for not knowing the proper terminology for asking this kind of question. That might be why I couldn't find an answer.
EDIT: The code I wrote was just an example; this is a general question. For example, let's assume I have a template used both for creating and editing users. The User object has a getName() function that returns their name.
When creating a new user, the 'name' input should be empty. When editing a user, the 'name' input should be filled with the user's name. Of course, $user isn't set in the former, but it's set on the latter.
Having <input value="<?php $user->getName() ?? '' ?>"> would be perfect, but throws an error. <input value="<?php isset($user) ? $user->getName() : '' ?>"> works, but I find the former more readable, so I would like to know if there's a way to make it work.
I know that $user->name ?? '' works, but for some data functions are necessary / preferable.

the problem that ?? and ? working not as you expected;
see example:
<?php
$string = "";
var_dump($string ?? 'ups'); // output ""
var_dump($string ? $string : 'ups'); //output "ups"
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand. manual
so it means:
$string ?? 'ups' is equal to isset($string) && $string !== null which is true for an empty string
and
$string ? $string : 'ups' is equal to $string == true ? $string : 'ups' which is false for empty string

Related

How do best check a string in PHP to avoid warnings

Simple question but it comes up all the time ... what is the best way to check variables in PHP. Looking for opinions / advice. In examples below assume $pricing could be not defined, correctly defined as 'price', or incorrectly defined as array(), etc..
//Method A ?
echo (!empty($pricing) && (string) $pricing == 'price' ? 'selected="true"' : '');
//Method B ?
echo (isset($pricing) && $pricing == 'price' ? 'selected="true"' : '');
// Method C ?
/// your idea ?
Method C: don't handle $pricing being undefined or of the wrong type in this expression.
By the time you reach this expression in your code, you should have already verified that the variable you're going to use exists and checked its type, and thrown an exception if it isn't what it's supposed to be, whether you do that explicitly or through a type declaration in a method.
By casting it to a string, or ignoring it if it doesn't exist, you may be covering up a potential problem that should cause an exception. If it's not a string, then something went wrong earlier in your code that you need to fix.
So just let your expression do one thing instead of multiple things.
echo $pricing == 'price' ? 'selected="true"' : '';
Then, if you see undefined variable notices in your error log, go back and fix the problem at the source (i.e. the place where $pricing was defined or should have been.)
If you're using PHP 7+, you have the null-coalesce operator (??) to compact the expression:
($pricing ?? '') === 'price' and print 'selected="true"';
Try it online at 3v4l.org.
Let's break that down:
($pricing ?? '') gracefully handles the scenario where $pricing has not been defined. If defined, this expression returns the defined value of $pricing: otherwise, it returns the empty string ''.
=== 'price' compares the now-defined value against exactly the value we are looking for. You can extend this test, of course. Like, if you had a set of defined values, you could instead use an in_array check.
and print 'selected="true"' reacts to the boolean result of the prior test, printing the desired value in the case of a match. Since outputting an empty string is equivalent to no output at all, we can simply use the and logical operator to conditionally output. Note that echo cannot be used here, as it's a language construct. Instead use print, printf, var_dump, etc.
That said, the emerging idiom for defaulting a potentially-undefined value uses the null-coalesce operator like:
$pricing = ($pricing ?? '');
I suggest defaulting in this way, versus the inline check given above, because it ensures $pricing is defined from that spot on. Said another way, don't litter your code with ($pricing ?? '') === 'price' checks: just do it once and be done with it.
As an aside, if you wanted to do multiple things on this condition, you could use an anonymous on-call:
($pricing ?? '') === 'price' and (function() {
echo 'this';
echo 'that';
})();
But I would not recommend these gymnastics.
I would write it this way:
echo (isset($pricing) && $pricing === 'price' ? 'selected="true"' : '');
This accomplishes the following:
condition evaluates to false if $pricing is undefined
condition evaluates to false if $pricing is not the same as 'price'
Finally, you are comparing with a specific value, anything other than that value will equate to false anyway, so checking for !empty() is redundant in this case.
Be sure to use the strict ( === ) comparison though, as if("some string" == 0) will return `true ( source ).
EDIT: Also, if you are unsure whether or not the variable has been defined (for example when working with $_POST), using isset() will save you a lot of trouble.

isset PHP isset($_GET['something']) ? $_GET['something'] : ''

I am looking to expand on my PHP knowledge, and I came across something I am not sure what it is or how to even search for it. I am looking at php.net isset code, and I see isset($_GET['something']) ? $_GET['something'] : ''
I understand normal isset operations, such as if(isset($_GET['something']){ If something is exists, then it is set and we will do something } but I don't understand the ?, repeating the get again, the : or the ''. Can someone help break this down for me or at least point me in the right direction?
It's commonly referred to as 'shorthand' or the Ternary Operator.
$test = isset($_GET['something']) ? $_GET['something'] : '';
means
if(isset($_GET['something'])) {
$test = $_GET['something'];
} else {
$test = '';
}
To break it down:
$test = ... // assign variable
isset(...) // test
? ... // if test is true, do ... (equivalent to if)
: ... // otherwise... (equivalent to else)
Or...
// test --v
if(isset(...)) { // if test is true, do ... (equivalent to ?)
$test = // assign variable
} else { // otherwise... (equivalent to :)
In PHP 7 you can write it even shorter:
$age = $_GET['age'] ?? 27;
This means that the $age variable will be set to the age parameter if it is provided in the URL, or it will default to 27.
See all new features of PHP 7.
That's called a ternary operator and it's mainly used in place of an if-else statement.
In the example you gave it can be used to retrieve a value from an array given isset returns true
isset($_GET['something']) ? $_GET['something'] : ''
is equivalent to
if (isset($_GET['something'])) {
echo "Your error message!";
} else {
$test = $_GET['something'];
}
echo $test;
Of course it's not much use unless you assign it to something, and possibly even assign a default value for a user submitted value.
$username = isset($_GET['username']) ? $_GET['username'] : 'anonymous'
You have encountered the ternary operator. It's purpose is that of a basic if-else statement. The following pieces of code do the same thing.
Ternary:
$something = isset($_GET['something']) ? $_GET['something'] : "failed";
If-else:
if (isset($_GET['something'])) {
$something = $_GET['something'];
} else {
$something = "failed";
}
It is called the ternary operator. It is shorthand for an if-else block. See here for an example http://www.php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary
? is called Ternary (conditional) operator : example
What you're looking at is called a Ternary Operator, and you can find the PHP implementation here. It's an if else statement.
if (isset($_GET['something']) == true) {
thing = isset($_GET['something']);
} else {
thing = "";
}
If you want an empty string default then a preferred way is one of these (depending on your need):
$str_value = strval($_GET['something']);
$trimmed_value = trim($_GET['something']);
$int_value = intval($_GET['somenumber']);
If the url parameter something doesn't exist in the url then $_GET['something'] will return null
strval($_GET['something']) -> strval(null) -> ""
and your variable $value is set to an empty string.
trim() might be prefered over strval() depending on code (e.g. a Name parameter might want to use it)
intval() if only numeric values are expected and the default is zero. intval(null) -> 0
Cases to consider:
...&something=value1&key2=value2 (typical)
...&key2=value2 (parameter missing from url $_GET will return null for it)
...&something=+++&key2=value (parameter is " ")
Why this is a preferred approach:
It fits neatly on one line and is clear what's going on.
It's readable than $value = isset($_GET['something']) ? $_GET['something'] : '';
Lower risk of copy/paste mistake or a typo: $value=isset($_GET['something'])?$_GET['somthing']:'';
It's compatible with older and newer php.
Update
Strict mode may require something like this:
$str_value = strval(#$_GET['something']);
$trimmed_value = trim(#$_GET['something']);
$int_value = intval(#$_GET['somenumber']);

Using short circuiting to get first non-null variable

What's the equivalent of the following (based in JS style) in PHP:
echo $post['story'] || $post['message'] || $post['name'];
So if story exists then post that; or if message exist post that, etc...
It would be (PHP 5.3+):
echo $post['story'] ?: $post['message'] ?: $post['name'];
And for PHP 7:
echo $post['story'] ?? $post['message'] ?? $post['name'];
There is a one-liner for that, but it's not exactly shorter:
echo current(array_filter(array($post['story'], $post['message'], $post['name'])));
array_filter would return you all non-null entries from the list of alternatives. And current just gets the first entry from the filtered list.
Since both or and || do not return one of their operands that's not possible.
You could write a simple function for it though:
function firstset() {
$args = func_get_args();
foreach($args as $arg) {
if($arg) return $arg;
}
return $args[-1];
}
As of PHP 7, you can use the null coalescing operator:
The null coalescing operator (??) has been added as syntactic sugar
for the common case of needing to use a ternary in conjunction with
isset(). It returns its first operand if it exists and is not NULL;
otherwise it returns its second operand.
// Coalescing can be chained: this will return the first
// defined value out of $_GET['user'], $_POST['user'], and
// 'nobody'.
$username = $_GET['user'] ?? $_POST['user'] ?? 'nobody';
Building on Adam's answer, you could use the error control operator to help suppress the errors generated when the variables aren't set.
echo #$post['story'] ?: #$post['message'] ?: #$post['name'];
http://php.net/manual/en/language.operators.errorcontrol.php
You can try it
<?php
echo array_shift(array_values(array_filter($post)));
?>
That syntax would echo 1 if any of these are set and not false, and 0 if not.
Here's a one line way of doing this which works and which can be extended for any number of options:
echo isset($post['story']) ? $post['story'] : isset($post['message']) ? $post['message'] : $post['name'];
... pretty ugly though. Edit: Mario's is better than mine since it respects your chosen arbitrary order like this does, but unlike this, it doesn't keep getting uglier with each new option you add.
Because variety is the spice of life:
echo key(array_intersect(array_flip($post), array('story', 'message', 'name')));

How to set default value to a string in PHP if another string is empty?

Best example would be to show you how is this solved in Javascript:
var someString = someEmptyString || 'new text value';
In this javascript example, we have detected that 'someEmptyString' is empty and automatically set the value to 'new text value'. Is this possible in PHP and what's the shortest (code) way to do it?
This is how I do it now:
if ($someEmptyString == "")
$someString = 'new text value'; else $someString = $someEmptyString;
This is bugging me for quite some time and I would be very grateful if someone knows a better way to do this. Thank you!
You can use the ternary operator ?:.
If you have PHP 5.3, this is very elegant:
$someString = $someEmptyString ?: 'new text value';
Before 5.3, it needs to be a bit more verbose:
$someString = $someEmptyString ? $someEmptyString : 'new text value';
$someString = (!isSet( $someEmptyString ) || empty( $someEmptyString ) )? "new text value" : $someEmptyString;
I think that would be the most correct way to do this. Check if that var is empty or if it's not set and run condition.
it's still a bit of code, but you shouldn't get any PHP warnings or errors when executed.
You can use the ternary operator
$someString = $someEmptyString ?: "New Text Value";
While ternary is more clear whats happening, You can also set the variable like this
($someString = $someEmptyString) || ($someString = "Default");
Works in all PHP versions, You can extend this to use more than 1 option failry easily also
($someString = $someEmptyString) ||
($someString = $someOtherEmptyString) ||
($someString = "Default");
which I personally find more readable than its ternary equivalent

Simple PHP isset test

This below does not seem to work how I would expect it, event though $_GET['friendid'] = 55 it is returning NULL
<?PHP
$_GET['friendid'] = 55;
$friendid = (!isset($_GET['friendid'])) ? $_GET['friendid'] : 'empty';
echo $friendid;
exit;
?>
As of PHP 7's release, you can use the null-coalescing operator (double "?") for this:
$var = $array["key"] ?? "default-value";
// which is synonymous to:
$var = isset($array["key"]) ? $array["key"] : "default-value";
In PHP 5.3+, if all you are checking on is a "truthy" value, you can use the "Elvis operator" (note that this does not check isset).
$var = $value ?: "default-value";
// which is synonymous to:
$var = $value ? $value : "default-value";
Remove the !. You don't want to negate the expression.
$friendid = isset($_GET['friendid']) ? $_GET['friendid'] : 'empty';
If you're lazy and risky, you can use error control operator # and short form of ternary operator.
$friendid = #$_GET['friendid']?: 'empty';
Currently you're working with the ternary operator:
$friendid = (!isset($_GET['friendid'])) ? $_GET['friendid'] : 'empty';
Break it down to an if-else statement and it looks like this:
if(!isset($_GET['friendid']))
$friendid = $_GET['friendid'];
else
$friendid = 'empty';
Look at what's really happening in the if statement:
!isset($_GET['friendid'])
Note the exclamation mark (!) in front of the isset function. It's another way to say, "the opposite of". What you're doing here is checking that there is no value already set in $_GET['friendid']. And if so, $friendid should take on that value.
But really, it would break since $_GET['friendid'] doesn't even exist. And you can't take the value of something that isn't there.
Taking it from the start, you have set a value for $_GET['friendid'], so that first if condition is now false and passes it on to the else option.
In this case, set the value of the $friendid variable to empty.
What you want is to remove the exclamation and then the value of $friendid will take on the value of $_GET['friendid'] if it has been previously set.
The best solution for this question, i.e. if you also need to 'check for the empty string', is empty().
$friendid = empty($_GET['friendid']) ? 'empty' : $_GET['friendid'];
empty() not only checks whether the variable is set, but additionally returns false if it is fed anything that could be considered 'empty', such as an empty string, empty array, the integer 0, boolean false, ...
I am using Null coalescing operator operator in if condition like this
if($myArr['user'] ?? false){
Which is equivalent to
if(isset($myArr['user']) && $myArr['user']){
From your reply to Philippe I think you need to have a look at the differences between empty and isset.
To summarise, isset() will return boolean TRUE if the variable exists. Hence, if you were to do
$fid = $_GET['friendid'] = "";
$exists = isset($fid);
$exists will be TRUE as $_GET['friendid'] exists. If this is not what you want I suggest you look into empty. Empty will return TRUE on the empty string (""), which seems to be what you are expecting. If you do use empty, please refer to the documentation I linked to, there are other cases where empty will return true where you may not expect it, these cases are explicitly documented at the above link.
if friendid is NOT set, friendid = friendid otherwise friendid = empty
Okay, I may have been having a similar issue not being familiar with the ! situation as jasondavis had.
Kind of confusing but finding out not having the ! as in... isset($avar) compared to !isset($avar) can make quite the difference.
So with the ! in place, is more stating a YES as in
since $_GET['friendid'] = 55; has been initialized...
tell me 'no' - the opposite - that it hasn't and set it to empty.
$friendid = (!isset($_GET['friendid'])) ? $_GET['friendid'] : 'empty';
where not having the ! tells me yes it has something in it, leave it be.
$friendid = (!isset($_GET['friendid'])) ? $_GET['friendid'] : 'empty';
Was far less confusing with if A$="" then.... work it. ( or if $A="" for those of PHP ).
I find this use of strings and variables all as strings to be very daunting at times. Even through the confusion, I can actually understand why... just makes things a tad difficult to grasp for me.
For me, if I need to know BOTH are true
key is set
value is truthy
and if not, use another result:
the shortest way is
$result = ($arr['b'] ?? 0) ?: $arr['a'];
(ie. if b is_set AND has a real value, use it. Otherwise use a)
So in this scenario:
$arr = ['a' => 'aaa', 'b' => 'bbb'];
$result = 'aaa'

Categories