Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

mkrell's avatar

PHP 8 Syntax speed difference?

Hey all. I discovered a weird performance thing about php 8.1.'s ?-> syntax.

I am serializing hundreds of objects into json-api format using Fractal. There are several layers down of relationships that it is serializing as well, and each object can have upwards of 20 fields.

I was trying to discover why serializing was slow and i discovered the following:

This:

            'created_at' => $item->created_at?->toIso8601String(),
            'updated_at' => $item->updated_at?->toIso8601String(),

was faster than this:

            'created_at' => empty($item->created_at) ? null : $item->created_at->toIso8601String(),
            'updated_at' => empty($item->created_at) ? null : $item->updated_at->toIso8601String(),

I tested and re-tested this a bunch of times; Fractal's serialization was about 300ms faster each time with the new syntax.

That seemed incredibly bizarre to me, so I ran a test in Tinkerwell:

$times = 10_000_000;

$startTime = microtime(true);
for ($i = 0; $i < $times; $i++){
  $carbon = new Carbon\Carbon();
  $save = empty($carbon) ? null : $carbon->toIso8601String();
}
$endTime = microtime(true);
echo (float)$endTime - (float)$startTime;

echo PHP_EOL;

$startTime = microtime(true);
for ($i = 0; $i < $times; $i++){
  $carbon = new Carbon\Carbon();
  $save = $carbon?->toIso8601String();
}
$endTime = microtime(true);
echo (float)$endTime - (float)$startTime;

And the ?-> syntax turned out to be slower by a few seconds!

Can anyone explain what's going on here? Why would using ?-> in fractal be faster but not in raw PHP?

0 likes
2 replies
LaryAI's avatar
Level 58

It's difficult to say exactly why the ?-> syntax would be faster in one context but slower in another without more information. However, it's worth noting that the empty() function is not equivalent to checking for null. empty() will return true for null, false, 0, '', and a few other values, so it's possible that the empty() check is adding some overhead in the second example.

One thing to try would be to change the empty() check to a strict null check ($item->created_at !== null) and see if that makes a difference.

Another thing to consider is that microbenchmarks like the one posted in the question can be misleading. It's possible that the difference in performance is due to some other factor that isn't being accounted for in the benchmark.

Without more information and testing, it's difficult to say for sure what's going on here.

Please or to participate in this conversation.