====== PHP RFC: clamp ======
* Version: 2
* Date: 2025-08-21
* Author: kylekatarnls, kylekatarnls@gmail.com
* Status: Draft
* Implementation: [[https://github.com/php/php-src/pull/19434]]
===== Introduction =====
''clamp'' checks if a comparable value is within a certain bound. If the value is in range it returns the value, if the value is not in range it returns the nearest bound.
This RFC is a continuation of [[https://wiki.php.net/rfc/clamp]] ([[https://github.com/php/php-src/pull/7191]])
Current userland implementations are handled in several ways, some of which use [[https://www.php.net/manual/en/function.min.php|min]] and [[https://www.php.net/manual/en/function.max.php|max]] to check the bound, which is costly and slow when called often. Because userland implementations are for the most part not cost-effective when called multiple times, a language implementation is desired.
echo clamp($percentage, min: 0, max: 100);
===== Proposal =====
This RFC proposes a new function: ''clamp''
clamp ( mixed $value, mixed $min, mixed $max ) : mixed
''clamp'' takes three arguments, a ''$num'', ''$min'' and ''$max'', checks if ''$num'' is within the bounds of ''$min'' and ''$max'', if in range, returns the value of ''$num'', otherwise, returns the nearest bound value, i.e. if ''$num > $max'' return ''$max'', if ''$num < $min'' return ''$min''.
If ''$min'' value is greater than ''$max'' value, a ''ValueError'' will be thrown, since that constitute an invalid bound.
If ''$min'' or ''$max'' is ''NAN'', a ''ValueError'' will be thrown.
==== Examples ====
clamp(2, min: 1, max: 3) // 2
clamp(0, min: 1, max: 3) // 1
clamp(6, min: 1, max: 3) // 3
clamp(2, 1.3, 3.4) // 2
clamp(2.5, 1, 3) // 2.5
clamp(2.5, 1.3, 3.4) // 2.5
clamp(0, 1.3, 3.4) // 1.3
clamp(M_PI, -INF, INF) // 3.141592653589793
clamp(NAN, 4, 6) // NAN
clamp("a", "c", "g") // "c"
clamp("d", "c", "g") // "d"
clamp(new \DateTimeImmutable('2025-08-01'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d') // 2025-08-15
clamp(new \DateTimeImmutable('2025-08-20'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d') // 2025-08-20
clamp(4, 8, 6)
// Throws ValueError: clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)
clamp(4, NAN, 6)
// Throws ValueError: clamp(): Argument #2 ($min) cannot be NAN
clamp(4, 6, NAN)
// Throws ValueError: clamp(): Argument #3 ($max) cannot be NAN
===== Backward Incompatible Changes =====
No backwards incompatible changes with PHP itself.
''clamp'' will no longer be available as a function name, could break potential userland implementations.
===== Proposed PHP Version(s) =====
* next PHP 8.x
===== RFC Impact =====
* **To SAPIs:** Function will be added to all PHP enviroments.
* **To Existing Extensions:** None
* **To Opcache:** None.
* **New Contants:** No new constants introduced.
* **php.ini defaults:** No changes to php.ini introduced.
===== Open Issues =====
To be found
===== Future Scope =====
This section should outline areas that you are not planning to work on in the scope of this RFC, but that might be iterated upon in the future by yourself or another contributor.
This helps with long-term planning and ensuring this RFC does not prevent future work.
===== Proposed Voting Choices =====
The vote will require 2/3 majority.
===== Implementation =====
RFC implementation can be found in the following pull request: [[https://github.com/php/php-src/pull/19434]].
===== References =====
* Implementation of similar methods/functions in other languages:
* [[https://en.cppreference.com/w/cpp/algorithm/clamp]]
* [[https://www.rdocumentation.org/packages/raster/versions/3.4-10/topics/clamp]]
* [[https://developer.mozilla.org/en-US/docs/Web/CSS/clamp()]]
* Implementation PR: [[https://github.com/php/php-src/issues/7191]]
* Discussion on the php.internals mailing list: [[https://externals.io/message/115050]]
* Announcement thread: [[https://externals.io/message/115076]]
===== Changelog =====
Main changes between first implementation ([[https://github.com/php/php-src/pull/7191]]) and this one ([[https://github.com/php/php-src/pull/19434]]) are:
* ''int|float'' became ''mixed'' (accept any comparable value) to better match the PHP "loosely typed language" rule
* Support string comparison (alphabetically sorted)
* Support ''DateTime''
* ''NAN'' handling was an open issue in the first implementation, this is now handled (''ValueError'' if passed as ''min'' or ''max'' argument, returned as is if passed as ''value'')
* New implementation has arity frameless support