array_key_exists and ?? in php 7.x - php

This code works in PHP 7.x
$array = ['asda' => ['asdasd']];
$var = $array['asda']['asdasd'] ?? "yes!";
echo $var;
If we replace ?? with ?: as we have in older PHP version, this code will not work, for example:
$array = ['asda' => ['asdasd']];
$var = $array['asda']['asdasd'] ? $array['asda']['asdasd'] : "yes!";
echo $var;
It means, we will get an error like:
Notice</b>: Undefined index: asdasd in <b>[...][...]</b> on line
So, can we use the first example in PHP 7.x without afraid about anything strange/unexpected in behind? I mean, is it safe to use this instead, for example, array_key_exists or isset

Use isset() to test if the element exists.
$var = isset($array['asda']['asdasd']) ? $array['asda']['asdasd'] : "yes!";
The old :? conditional operator is a simple if/then/else -- it tests the truthiness of the first expression, and then returns either the second or third expression depending on this. The test expression is executed normally, so if it involves undefined variables, indexes, or properties you'll get a normal warning about it.
The new ?? null-coalescing operator, on the other hand, tests whether the first expression is defined and not NULL, not just whether it's truthy. Since it does it's own check for whether the expression is defined, it doesn't produce a warning when it's not. It's specifically intended as a replacement for the isset() conditional.
See PHP ternary operator vs null coalescing operator

Related

How do I print an array value as a template tag as blank in shorthand, even if it's null?

If I have this in my main php file (eg. my controller)
$debate['title'] = NULL;
And this in my template file (eg. my views file), where I can include PHP with my HTML. Imagine that I'm using a template engine or PHP as a templating engine.
<?=$debate['title'];?>
Note the = after the <? that makes it a shorthand way to include php variables and array keys in my template, to be shown on an HTML web page.
Well now in PHP 7.4 onwards, if $debate['title'] is null, I get this error. (That's if the notice severity level of errors is setup to be displayed on your screen.)
Message: Trying to access array offset on value of type null
I know that Stack Overflow would want me to use isset() but using something like
<?php if (isset($debate['title'])) { echo "$debate[title]"; } ?>
It just doesn't have the same ring to it. It's not really shorthand, is it?
There is an operator in PHP(from version 7.0) called null coleascing operator which is denoted by two question marks(??). Null colescing operator can be helpful in your case. For example, you can simply write this code as below:
<?= $debate['title'] ?? '' ?>
which is equavalent to writing:
<?= isset($debate['title']) ? $debate['title'] : '' ?>
You can use the "null coalescing" operator (??) to provide a default value if the array value is null. The "null coalescing" operator returns the value of its left operand if it exists and is not null, and the value of its right operand otherwise.
For example:
<?=$debate['title'] ?? '';?>
This will print an empty string if $debate['title'] is null, and will print the value of $debate['title'] if it exists and is not null.
Alternatively, you can use the "ternary operator" (?:) to achieve the same effect:
<?=$debate['title'] !== null ? $debate['title'] : '';?>
This will also print an empty string if $debate['title'] is null, and will print the value of $debate['title'] if it exists and is not null.
Both of these approaches are shorthand ways to provide a default value for an array value in a template.
In general you can use the null coalescing operator, like
$debate['title'] ?? ''
If you pass this to a function, then you can apply the same inside the function parameters, like:
htmlspecialchars($debate['question'] ?? 'array is blank');
Please use ternary operator
when array value is null, it will print blank.
<?=$debate['title']= null;?>
<?= $debate['title'] ?: ''; ?>
Or if array value is not null, it will print the value
In order not to change your template file, you could assign the empty value ('') to the variable in your controller ($debate['title'] = ''), or use the ternary operator to perform this check ($debate['title'] ?: '').
The displayed error just indicates that you are trying to access a NULL value.

Is there a leaner way to write this logic?

So I have the following logic to return a value if it's in the array or just return the original value if it's not:
$trnTitle = $translateMap[$title];
if($trnTitle)
return $trnTitle;
return $title;
Is there a more sleek way to write this? I just feel like there's gotta be like one line I could write instead of calling the variable three times.
Since php 7 you can use the Null-Coalescing operator, if $translateMap[$title] is null, when not filled.
return $translateMap[$title] ?? $title;
See more information here:
http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.coalesce
I am not sure from your code example what you are trying to achieve for 100%. I see two ways how to look at it.
You do not know if index $title exists in array $translateMap. If it exists you return its value from array or return the index itself:
return $translateMap[$title] ?? $title; <== http://php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op
You know that index title exists in array translateMap and you are just checking if it's truthy. If it is truthy you return value from array otherwise index itself.
return $translateMap[$title] ?: $title; <== http://php.net/manual/en/control-structures.if.php#102060
Warning: This would fail if index $title does not exist in array $translateMap
Solution 2 is exactly what you have in your example
You can use the null coalescing operator, which looks like ??.
According to the official PHP documentation,
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.
So just use this:
return $translateMap[$title] ?? $title
Credit to Nigel Ren's, Vody's, and Manual Otto's comments.

Set null (default) if array element is undefined

I have a function to populate an Object.
public static function populateObj($data) {
$obj = new Obj();
$obj->setVal1($data['val1']);
$obj->setVal2($data['val2']);
$obj->setId($data['id']);
return $obj;
}
If all values are given with the parameter $data it works fine. But if someting is missing it throws an error.
Is there a shorter and easier or better way to set null as default than this:
$data['val1'] ? $obj->setVal1($data['val1']) : $obj->setVal1(null);
...
You can merge with a default array, then $data will contain all of those keys:
$data = array_merge(['val1'=>null, 'val2'=>null, 'id'=>null], $data);
In PHP >= 7.0 you can use the Null Coalescing Operator:
$obj->setVal1($data['val1'] ?? null);
That is perhaps the fastest (fewest typed words) way to do it. Another that may be faster, if it is worth it to you is to make a class and a constructor with default values. array_pad() with array_merge() may also be worth looking at, depending on your application.
In PHP 7+ you can use ?? a.k.a null coalesce
$obj->setVal1($data['val1']??null);
$obj->setVal2($data['val2']??null);
$obj->setId($data['id']??null);
See an example here
The null coalescing operator (??) has been added (in PHP7) 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.

Alternative to isset(user_input) in php

I was wondering whether is another way to check if a variable coming from user input is set and not null, besides (the obvious choice) isset().
In some cases, we may not be using $_POST to get the value, but some similar custom function. isset() can not be used on the result of a function call, so an alternative way to perform the same check must be made. Now, isset() verifies two things:
Whether the value was set.
Whether the value is null. But there is some difference between assigning a variable the null value ( $variable = NULL; ) and getting a null value due to empty input fields. Or at least so I read.
So, is there a good way of checking both these requirements without using isset() ?
The equivalent of isset($var) for a function return value is func() === null.
isset basically does a !== null comparison, without throwing an error if the tested variable does not exist. This is a non-issue for function return values, since a) functions must exist (or PHP will exit with a fatal error) and b) a function always returns something, at least null. So all you really need to do is to check for null, no isset necessary.
I've written about this extensively here: The Definitive Guide To PHP's isset And empty.
Beyond this, it depends on what exactly you want to check:
test if a key was submitted via GET/POST: isset($_POST['key'])
test if there's a value and whether it's not == false: !empty($_POST['key'])
test if it's a non-empty string: isset($_POST['key']) && strlen($_POST['key'])
perhaps much more complex validations: filter_input
Here are some options...
PHP 7.4+ : null coalescing assignment operator
$variable ??= '';
PHP 7.0+ : null coalescing operator
$variable = $var ?? '';
PHP 5.3+ : ternary operator
isset($variable) ?: $var = '';
You can also use !empty() in place of isset()
the function !empty() works for both isset() and check whether the value of any string is not null, 0 or any empty string.
I usually prefer !empty() whenever I need to compare variable existence or in terms of its value.
The best way is isset but if you insist ... try empty() and strlen() Function to check wether it is empty or string lenghth is bigger than so many characters.
strlen() returns a number, length of the variable passed to it.
empty() checks if it has character in it or if it is null. with empty() you have to be becareful because some functions return 0 or false which is not considered empty.
if(!empty($var))....
OR
if(strlen($var)>2)...
I do it in most cases like this:
$v = my_func();
if (isset($v) and $v) {
...
}

Using isset or # to test/assign a superglobal variable

Can I use # instead of isset to assign or test superglobal variable ?
Use this :
$foo = intval(#$_POST['bar']);
Instead of this :
$foo = isset($_POST['bar']) ? intval($_POST['bar']) : 0;
works without generate a notice but maybe for some reasons, the use of isset is better than # ?
isset with the ternary operator would be cleaner and easier to read.
Error suppression on the other hand, has some overhead costs:
I first built a simple test that would loop a million times accessing
a variable with and without the suppression operator prepended. The
differences were small, yet noticeable. Using the suppression operator
ended up taking 40% longer to execute.
Sources:
http://seanmonstar.com/post/909029460/php-error-suppression-performance
http://www.lunawebs.com/blog/2010/06/07/another-look-at-php-error-supression-performance/
There's an alternative to using # for those of us who are tired of using isset() before pulling the value:
function iisset(&$var, $default = null) {
return isset($var) ? $var : $default;
}
There is no notice generated for passing a non-existent array index as a reference. So for your example you would use:
$foo = intval(iisset($_POST['bar'], 0));
I wish PHP had a function like this built-in. The amount of isset checks followed immediately by the retrieval of that array index is so common that without a function like this there is a ridiculous amount of extra code.
Update:
PHP 7 now has a built-in operator known as the null coalesce operator:
$foo = intval($_POST['bar'] ?? 0);

Categories