What is this: `method()?->`

I’ve seen it used in a kirbycast:

$album->image()?->url()

As far as I understand, this will execute url() method only if image is true/truish ? correct ?

where does it come from ? is it documented?

I mean I already love it <3

Thanks

1 Like

almost. only if the thing before the question mark is !== null. if it is null then stop execution of following function calls and return null.

its called the nullsafe operator. a nice introduction can be found here:

1 Like

Does an empty field always return null ?

If a field does not exist , so if a method does not exist, do we get null ?

Thanks

No. You can easily test what you get yourself by doing

dump($page->doesNotExist());

This will always give you a field object, no matter if the field exists or is empty.

There are methods to check if a field exists or is empty.

Hmmm

So we cannot use null safe op. as a substitute of isNotEmpty() then ?

For example:

$d->duration()?->toDate("H'h' mm'' ss''''")

instead of:

$d->duration()->isNotEmpty() ? $d->duration()->toDate("H'h' mm'' ss''''") : '';

In the case of image() , the method does explicitly return null if no image is found, that is why we can use it, I understand that.

No.

The purpose of the null safe operator is to prevent errors of calling a member method on null. So using it only makes sense if the method you call is supposed to return an object but can return null, and you want to call a member method of this objects’s class.

1 Like

Now that we are at it, is there any method that allows for empty checking then chain, that is not a ternary etc ?

I always hated the verbosity and repetition of a typical:

<?= $d->elementdescription()->isNotEmpty() ? $d->elementdescription()->inline() : '' ?>

And for a moment thought I could do:

(wrong)
<?= $d->elementdescription()?->inline() ?>

Any equivalents ?

Assuming that echoing an empty field is not considered bad practice for some reason.

Thank you

Well, the problem with particularly the inline method is, that the strip_tags() method that is used internally in the inline() method expects a string instead of null:

'inline' => function (Field $field) {
    $field->value = strip_tags($field->value, Html::$inlineList);
    return $field;
},

I think that is something that should be fixed in Kirby (`inline` field method throws when empty field value is passed · Issue #5061 · getkirby/kirby · GitHub). Usually, you should just be able to call

<?= $page->emptyOrNotExisting()->inline() ?>

So the issue why you get an error here has nothing to do with calling a member method on null, because emptyOrNotExisting() does return a field. It is something that happens inside the method.

Oh I see,

I actually meant any usual operation on fields that needs a check on the field containing anything, such as:

<?= $page->startdate()->isNotEmpty() ? $page->startdate()->toDate('MMM d - ') : '' ?>

<?= $artwork->elementdescription()->isNotEmpty() ? $artwork->elementdescription()->kirbytextinline() : '' ?>

etc, which are very common in my code.

Assuming that inline() is the only method with that particular behaviour.

Thanks

As I said, checking if the field is empty in this case is not necessary at all. I don’t know why you are doing it. It makes sense in such a case:

<?php if ($page->startdate()->isNotEmpty()) : ?>
<div class="whatever"><?= $page->startdate()->toDate('MMM d - ') ?></div>
<?php endif ?>

i.e to prevent outputting an empty div.

Ok, I wasn’t aware of that, thank you.

That’s also why there are places where the null-safe operator makes sense and where it doesn’t. For example if I just want to ouput an image url if the image exists:

<?= $page->image()?->url() ?>

But it doesn’t make sense when I want to do the following:

<?php if ($image = $page->image()?>
<figure>
  <img src="<?= $image->url() ?>">
  <figcaption><?= $image->caption() ?></figcaption>
</figure>
<?php endif ?>

Of course I could do:

<figure>
  <img src="<?= $page->image()?->url() ?>">
  <figcaption><?= $page->image()?->caption() ?></figcaption>
</figure>

But that would be silly.

1 Like

Ok

But If I chain methods, and the field is empty, and there is no null-safe, the second method may be called upon null and throw an exception, correct?

$page->field()->method1()->method2()

If that is correct, then it may be I encountered one of these situations and I started checking for isNotEmpty by default, even when not chaining methods, which is not necessary as I see…

The important thing to understand is

  1. $page->field() always returns a field object, no matter if this field exists or not, otherwise it wouldn’t even be possible to call $page->field()->exists(), because that then would throw a “calling member method exists on null”.

  2. Any field method (i.e. what you call on that field, e.g. $page->date()->toDate() can return something different. Some of these methods return a field object again, for example $page->doesnotexist()->kt(), so you could call $page->doesnotexist()->kt()->esc() without issues.

  3. However, some field methods do not return a field object, but a string, integer, boolean, array, or other type of object so you cannot chain another field method onto it, even if the field is not empty, these are for example, toSlug(), toDate(), toBool(), words(), toPages() etc…

In most cases, our Reference tells you for every single method what it returns.