5

I am often in a situation when the variable can be object or null.

When I put data into the database I have to stick with something like this:

// @var User|null $user
$data['id_user'] = $user!==null ? $user->getId() : null;

Is there any way to shorthen this? I am aware of ??, but this is somewhat opposite.

I am using PHP 7.1.

Gomi
  • 632
  • 1
  • 7
  • 23
  • https://stackoverflow.com/q/1993409/534109 - you're looking for the elvis operator – Tieson T. Jan 18 '19 at 16:35
  • That won't exactly work in this case though will it? The Elvis operator would be equivalent to `$user ? $user : null;` (so `$user` will be assigned rather than `$user->getId()`) - and you don't want to do `$user->getId() ?: null` in case the `$user` object itself is `null` (thus calling a method on `null`)... uh huh huh. Thankyouverymuch. – CD001 Jan 18 '19 at 16:39
  • Elvis operator will also generate E_NOTICE if `$user` is undefined. – Alex Howansky Jan 18 '19 at 16:42
  • Actually, your existing code generates E_NOTICE as well, you should probably use something like: `isset($user) ? $user->getId() : null;` – Alex Howansky Jan 18 '19 at 16:48
  • ^ or for the super-cautious a mix of `isset()`, `is_object()` and `method_exists()` ... O_o ... Barmar's solution/hack (depending on perspective) is looking better by the minute. – CD001 Jan 18 '19 at 16:52
  • Actually, I use `$user!==null` there. My mistake, sorry. I've edited the question accordingly. – Gomi Jan 18 '19 at 17:04
  • Please see my updated answer below about the nullsafe operator. I think it is what you wanted. – still_dreaming_1 Nov 10 '20 at 14:06

3 Answers3

1

As of PHP 8, there is the nullsafe operator ?->. With it you could refactor your code like this:

// @var User|null $user
$data['id_user'] = $user?->getId();

Prior to PHP 8, you could utilize automatic bool converting to take advantage of the fact that, when converting to bool, null is considered false, but other objects are not (except apparently SimpleXML objects created from empty tags are also considered false). So you could shorten your example to the following:

// @var User|null $user
$data['id_user'] = $user ? $user->getId() : null;

However, this might be less readable since the ? might imply to some people you are working with a bool to begin with, or it could make the reader have to think about how null gets converted to bool. Your original code is more explicit, and thus potentially more readable. In order to make brains work less hard, I often at least consider avoiding using "not equals" whenever possible, and just go with a straight "equals". So you could refactor your code to be like this:

// @var User|null $user
$data['id_user'] = $user === null ? null : $user->getId();

In this particular case, I think that trick (avoiding "not equals") works fairly well, but sometimes counterintuitively, the code is still more naturally readable to just use a "not equals" anyways.

still_dreaming_1
  • 8,661
  • 6
  • 39
  • 56
0

If you define a __toString() class in your user object, and have that return the id, then you can use the null coalesce operator:

class User
{
    public function __toString()
    {
        return (string) $this->getId();
    }
}

$data['id_user'] = $user ?? null;

This will not generate any warnings either.

However, it doesn't help too much if you have more than one field you want to do this with.

Alex Howansky
  • 50,515
  • 8
  • 78
  • 98
-2

I don't think there's an operator that does precisely that.

The closest is the @ error-suppression operator:

$data['id_user'] = @$user->getId();

If $user->getId() gets an error, the error message is suppressed and the value is null.

Barmar
  • 741,623
  • 53
  • 500
  • 612