How can I type cast when using the null coalescing operator?
Asked Answered
J

5

10

Say I have this:

$username = (string) $inputs['username'] ?? null;

If $inputs['username'] is set then I want it to cast to string. If it's not set then $username should be null.

However, at the moment if $inputs['username'] is not set it will be an empty string instead of null.

How can I fix this? Or is this intentional behaviour?

Jacobean answered 14/5, 2018 at 20:26 Comment(3)
I think what might be happening is that you are casting username which is null, to a string. Then the coalesce operator is seeing the empty string as a value. Therefore the value is set, and it returns the empty string. Why do you need the string type cast?Isotone
Yes, you're right. I was using ?? to cut down on the isset() code you'd normally use with ?: because of working on an application where types need to be strictly enforced.Jacobean
Do nullable types solve the problem? $username = (string?) $inputs['username'] ?? nullEosin
H
9

You can only use the null-coalesce operator if the value you want to return in the non-null case is the same as the value you're testing. But in your case you want to cast it when returning.

So need to use the regular conditional operator and test the value explicitly.

$username = isset($input['username']) ? (string) $input['username'] : null;
Harmonic answered 14/5, 2018 at 20:52 Comment(2)
Thanks Barmar, I assume that means there's no way around it, i.e. this is just the way it's designed? I was hoping to replace all the isset().Jacobean
It can only be used to simplify isset(expression) ? expression : null. If it doesn't match that pattern, it won't work.Harmonic
B
5

For my projects I use one of these lines:

$array = [
    'a' => 1000
];

$boolA = (bool)($array['a'] ?? false); // bool(true)
$boolB = (bool)($array['b'] ?? false); // bool(false)
$boolC = (bool)($array['c'] ?? false) ?: null; // null

$intA = (int)($array['a'] ?? 0); // int(1000)
$intB = (int)($array['b'] ?? 0); // int(0)
$intC = (int)($array['c'] ?? 0) ?: null; // NULL

$stringA = (string)($array['a'] ?? ''); // string(4) "1000"
$stringB = (string)($array['b'] ?? ''); // string(0) ""
$stringC = (string)($array['a'] ?? '') ?: null; // string(4) "1000"
$stringD = (string)($array['d'] ?? '') ?: null; // NULL
$stringE = (isset($array['e']) ? (string)$array['e'] : null); // NULL

$arrayA = (array)($array['a'] ?? []); // [ 0 => int(1000) ]
$arrayB = (array)($array['b'] ?? []); // []
$arrayC = (array)($array['c'] ?? []) ?: null; // null

var_dump($boolA);
var_dump($boolB);
var_dump($boolC);

var_dump($intA);
var_dump($intB);
var_dump($intc);

var_dump($stringA);
var_dump($stringB);
var_dump($stringC);
var_dump($stringD);
var_dump($stringE);

var_dump($arrayA);
var_dump($arrayB);
var_dump($arrayC);

OUTPUT:

bool(true)
bool(false)
NULL

int(1000)
int(0)
NULL

string(4) "1000"
string(0) ""
string(4) "1000"
NULL
NULL

array(1) {
  [0] => int(1000)
}
array(0) { }
NULL
Blinding answered 9/6, 2022 at 9:54 Comment(2)
why you're making default value null instead of expected value, like false, 0?Iata
@YourCommonSense You're right, it's better to use expected values! I changed my answer.Blinding
S
2

I suppose you could convert "falsey" values of the null-coalesced string typecast back to null.

$username = (string) ($inputs['username'] ?? '') ?: null;

It's kind of odd looking, but I think it would produce what you want without using isset. In this case, the '' doesn't matter because it will never be used; it could be anything falsey.

Snowdrift answered 14/5, 2018 at 20:50 Comment(1)
This is the solution I've been using. It's very useful for checking truthy which means null, false, 0, "" wont get through. Must know what truthy does to not be caught out by this though!Untinged
B
1

Old school:

<?php
$bar = null;
if(isset($foo))
    $bar = (string) $foo;

You could drop the null assignment:

isset($foo) && $bar = (string) $foo;
Breger answered 14/5, 2018 at 20:59 Comment(1)
Can this be golfed to: isset($foo) && $bar = "$foo";?Breger
G
0

I'm not entirely sure what you're trying to do but it looks like you're casting in the wrong place.

You can do something like this:

$username = $inputs['username'] ?? null;

// cast $username to string 
if ($username && $username = (string) $username){
   // your code here
}
Golding answered 14/5, 2018 at 20:38 Comment(4)
Thanks, goal was to use ?? though in order to cut down on code, but doesn't seem it's possible to type cast in it.Jacobean
Ahh.. I see..so you're trying to reduce the number of lines so your code looks elegant, yes? :)Golding
More readable / elegant, yes, as this pattern is heavily used.Jacobean
Tempting though it may seem, the problem with this kind of "elegance" is that sometimes it's not easily readable by the next guy. If the aim is to save two or three lines of space then I'd say it's probably not worth it. :)Golding

© 2022 - 2024 — McMap. All rights reserved.