Make WordPress Core

Opened 2 months ago

Closed 41 hours ago

Last modified 41 hours ago

#59450 closed enhancement (fixed)

Initialize $url variable later in get_bloginfo()

Reported by: cybr's profile Cybr Owned by: flixos90's profile flixos90
Milestone: 6.5 Priority: normal
Severity: minor Version: 2.3
Component: General Keywords: has-patch commit
Focuses: performance Cc:


get_bloginfo() is a popular function. Alas, it performs checks for an often unused parameter: $url.

Moreover, the ! str_contains() chain can be exchanged for a simpler preg_match().
See, for performance:

The attached patch will address both issues.

Note that the performance impact is mostly due to the use of NOT and writing to a variable.
Here's the performance benchmark of that:
When we fix that and then compare it to preg_match(), it becomes a matter of preference:

Still, str_contains() relies on a polyfill for many sites.

It's been like this since WP 2.3, so it might be worthwhile to write a sniff for this as it went unnoticed for 16 years.

Attachments (1)

general-template.php.patch (594 bytes) - added by Cybr 2 months ago.

Download all attachments as: .zip

Change History (9)

#1 @swissspidy
2 months ago

  • Milestone changed from Awaiting Review to 6.5
  • Severity changed from normal to minor

Initializing the variable only when it's needed is reasonable.

I doubt the performance impact is that high though in a real world scenario, as the function is never used 100k times on a single page load :)
In fact, your benchmark shows that preg_match is slower even with 1e4 iterations.

#2 @swissspidy
2 months ago

  • Summary changed from Fix get_bloginfo to Initialize $url variable later in get_bloginfo()

#3 @Cybr
2 months ago

The 1e4 iterations are not part of the benchmark but the warmup. I found that the website shows inconsistent numbers, probably due to the way hrtime() interacts with the server or how it lazy loads PCRE -- I cannot tell. If you flip the warmup tests, the second will always be slower during -- everything thereafter is indicative of real-world performance. I should exclude those from the output in the future to alleviate confusion about this quirk.

The point I'm making about not writing to variables is that the entire codebase is trying to write variables before reading them. This often happens needlessly, also in apply_filters(), albeit obscure: This is the aftermath of supporting PHP 5.2 for far too long, accumulating code debt that should be undone if we wish to make WordPress load in under 0.01 seconds; I'm certain that number is attainable.

Last edited 2 months ago by Cybr (previous) (diff)

#4 @swissspidy
2 months ago

The 1e4 iterations are not part of the benchmark but the warmup.

You used 1e3 for warmup and ie5 for the benchmark. In my testing I reduced the 1e5 to 1e4. That's what my comment was referring to.

But yes, I agree, overall the numbers are inconsistent, which is why I don't see the need in changing those str_contains calls to preg_match.

Anyhow, as we have already established here, it makes sense to initialize the variable later.

#5 @flixos90
42 hours ago

  • Keywords commit added
  • Owner set to flixos90
  • Status changed from new to reviewing
  • Type changed from defect (bug) to enhancement

Since the str_contains() vs preg_match() comparison doesn't show a clear winner in performance, it's likely insignificant regardless. So given the existing code uses str_contains(), we should probably just stick to that.

So what I'm leaning towards is modifying general-template.php.patch to use the following in the if clause (instead of preg_match()):
str_contains( $show, 'url' ) || str_contains( $show, 'directory' ) || str_contains( $show, 'home' )

#7 @flixos90
41 hours ago

  • Resolution set to fixed
  • Status changed from reviewing to closed

In 57170:

General: Avoid early initialization of variable in get_bloginfo().

This is a very minor, yet simple performance optimization in a commonly called function, avoiding unnecessary initialization of the $url variable when it may not be needed. The conditional is simple enough to not use a variable altogether.

Props Cybr, swissspidy.
Fixes #59450.

Note: See TracTickets for help on using tickets.