Make WordPress Core

Opened 5 months ago

Closed 3 months ago

#65143 closed enhancement (fixed)

Add polyfill for PHP 8.6's clamp() function

Reported by: Soean Owned by: westonruter
Priority: normal Milestone: 7.1
Component: General Version:
Severity: normal Keywords: has-patch
Cc: Focuses: php-compatibility

Description

PHP 8.6 introduces a new built-in clamp() function (​RFC) that clamps a value within a given range. If the value is within bounds, it is returned as-is; otherwise, the nearest bound is returned.

Since WordPress supports PHP 7.4 and above a polyfill is needed so WordPress and plugins can safely use clamp() without checking the PHP version.

Proposed Behavior

  • If $value is within [$min, $max], returns $value.
  • If $value > $max, returns $max.
  • If $value < $min, returns $min.
  • Throws ValueError (PHP >= 8.0) or InvalidArgumentException (PHP 7.x) if $min > $max or if $min/$max is NAN.

The polyfill relies on a new private helper _wp_throw_value_error(), which conditionally throws ValueError on PHP >= 8.0 and falls back to InvalidArgumentException on PHP 7.x — consistent with how ​Symfony handles the same compatibility problem.

Usage Examples

clamp( 5, 0, 100 );   // 5
clamp( -5, 0, 100 );  // 0
clamp( 105, 0, 100 ); // 100

clamp( 3.14, 0, 20 );  // 3.14
clamp( 3.14, 10, 20 ); // 10

clamp( 'P', 'A', 'Z' ); // "P"
clamp( 'P', 'X', 'Z' ); // "X"

clamp( new DateTimeImmutable('2026-01-08'), new DateTimeImmutable('2026-01-01'), new DateTimeImmutable('2026-12-31') );
// DateTimeImmutable('2026-01-08')

clamp( 4, NAN, 6 ); // ValueError: clamp(): Argument #2 ($min) cannot be NAN
clamp( 4, 8, 6 );   // ValueError: clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)

Changes

  • src/wp-includes/compat.php: Add _wp_throw_value_error() helper and clamp() polyfill.

References

Change History (9)

This ticket was mentioned in ​PR #11669 on ​WordPress/wordpress-develop by ​@Soean.


5 months ago
#1

  • Keywords has-patch added

This pull request adds a polyfill for the new PHP 8.6 clamp() function to ensure compatibility with older PHP versions. It also introduces a helper function to throw the appropriate error type depending on the PHP version.

New function polyfills and helpers:

  • Added _wp_throw_value_error() to throw a ValueError on PHP 8.0+ or an InvalidArgumentException on PHP 7.x, providing consistent error handling for polyfills.
  • Added a polyfill for the clamp() function, which restricts a value within a specified minimum and maximum, including input validation and appropriate error throwing for invalid arguments.

Trac ticket: https://core.trac.wordpress.org/ticket/65143

## Use of AI Tools

AI assistance: Yes
Tool(s): GitHub Copilot
Model(s): Claude Opus 4.6
Used for: Code docs.

#3 @westonruter
5 months ago

Are there places where clamp() should be used in core? I think generally a polyfill would be added if it is actually used.

#4 @Soean
5 months ago

@westonruter I added two places to the PR, where we can use it in Core.

Providing a polyfill in WordPress Core ensures that plugin and theme developers can use it consistently across all supported PHP versions without needing to implement their own.

#5 @westonruter
5 months ago

  • Milestone Awaiting Review → 7.1
  • Owner set to westonruter
  • Status new → reviewing

Great. Let's get this in the queue for 7.1.

#6 @wildworks
3 months ago

As the release of 7.1 Beta1 is approaching, I would like to check the status of this ticket. What is the status of the attached PR?

#7 @westonruter
3 months ago

Looking at this today.

​@westonruter commented on ​PR #11669:


3 months ago
#8

  • Added _wp_throw_value_error() to throw a ValueError on PHP 8.0+ or an InvalidArgumentException on PHP 7.x, providing consistent error handling for polyfills.

In d33db07, I opted to move this into a closure since it was only being used in one function. We can re-extract if we need to use it in another polyfill.

I added the necessary PHPDoc to ensure the clamp() function doesn't introduce PHPStan errors due to the mixed return type.

I also fixed the PHPStan issues with wp_get_typography_value_and_unit() which were causing PHPStan errors with the new clamp() usage. Similarly, I fixed the PHPStan errors in the other clamp() usage in embed.php by providing a type definition for the variable being clamped.

#9 @westonruter
3 months ago

  • Resolution → fixed
  • Status reviewing → closed

In 62719:

Code Modernization: Add a polyfill for PHP 8.6's clamp().

Introduce a clamp() polyfill in compat.php so that core, plugins, and themes can call the function on every supported PHP version without a version check. It returns the value when it lies within the bounds and the nearest bound otherwise, and throws a ValueError when $min is greater than $max or when either bound is NAN. On PHP 7.x, an InvalidArgumentException is thrown instead, since the ValueError class does not yet exist.

Adopt the function at the two places in core that were clamping via a nested min( max( … ) ): the oEmbed response width in get_oembed_response_data(), and the minimum font size factor in wp_get_typography_font_size_value().

Additionally, fix PHPStan errors in code that touches the newly-introduced clamp() usage. Add types to wp_get_typography_value_and_unit() and refactor the parsing to allow static analysis to identify the shape of $matches and avoid issues with passing special regex characters in units.

Developed in ​https://github.com/WordPress/wordpress-develop/pull/11669.
Follow-up to r35436, r54260, r55947.

Props soean, mukesh27, westonruter.
See #64898.
Fixes #65143.

Note: See TracTickets for help on using tickets.