In PHP 8.0, there is a new "nullsafe operator", spelled ?->
for exactly this purpose: it calls the method only if the value is not null.
The only part if can't do is the extra check on ->count()
, but as long as ->first()
returns null rather than an error on an empty set, this would work:
$imageUrl = $item?->getProduct()?->getMedia()?->first()?->getMedia()?->getUrl();
Unless and until you can upgrade to PHP 8, your best bet will be to look for ways to improve the API to avoid this problem in the first place. In line with the Law of Demeter, you could define additional methods so that you could write this:
$imageUrl = $item->hasProductMedia() ? $item->getProductMedia()->first()->getUrl() : null;
The implementation of hasProductMedia()
and getProductMedia()
still need those checks, but they're hidden away rather than written each time you need to access it.
Another approach is the "Null Object Pattern" (hat tip to Markus Zeller for mentioning this in comments). Instead of returning null, each method returns a special "empty object" satisfying the correct interface.
So $item->getProduct()
would never return null
, but might return a NullProduct
; calling getMedia()
on that, or any product without any media, would return an EmptyMediaList
; and so on. Eventually, you'd call getUrl()
on a NullMediaItem
, and it would give you a null value.