Skip to content

Commit c9033e5

Browse files
committed
[PHP 8.6] Add clamp function
1 parent 41ace00 commit c9033e5

File tree

9 files changed

+234
-0
lines changed

9 files changed

+234
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ Polyfills are provided for:
7979
- the `NoDiscard` attribute introduced in PHP 8.5;
8080
- the `array_first` and `array_last` functions introduced in PHP 8.5;
8181
- the `DelayedTargetValidation` attribute introduced in PHP 8.5;
82+
- the `clamp` function introduced in PHP 8.6;
8283

8384
It is strongly recommended to upgrade your PHP version and/or install the missing
8485
extensions whenever possible. This polyfill should be used only when there is no

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"symfony/polyfill-php83": "self.version",
3535
"symfony/polyfill-php84": "self.version",
3636
"symfony/polyfill-php85": "self.version",
37+
"symfony/polyfill-php86": "self.version",
3738
"symfony/polyfill-iconv": "self.version",
3839
"symfony/polyfill-intl-grapheme": "self.version",
3940
"symfony/polyfill-intl-icu": "self.version",

src/Php86/LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2025-present Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

src/Php86/Php86.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Polyfill\Php86;
13+
14+
/**
15+
* @author kylekatarnls <kylekatarnls@gmail.com>
16+
*
17+
* @internal
18+
*/
19+
final class Php86
20+
{
21+
/**
22+
* @template V
23+
* @template L
24+
* @template H
25+
*
26+
* @param V $value
27+
* @param L $min
28+
* @param H $max
29+
*
30+
* @return V|L|H
31+
*/
32+
public static function clamp($value, $min, $max)
33+
{
34+
if (\is_float($min) && \is_nan($min)) {
35+
self::throwValueErrorIfAvailable('clamp(): Argument #2 ($min) cannot be NAN');
36+
}
37+
38+
if (\is_float($max) && is_nan($max)) {
39+
self::throwValueErrorIfAvailable('clamp(): Argument #3 ($max) cannot be NAN');
40+
}
41+
42+
if ($max < $min) {
43+
self::throwValueErrorIfAvailable('clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)');
44+
}
45+
46+
if ($value < $min) {
47+
return $min;
48+
}
49+
50+
if ($value > $max) {
51+
return $max;
52+
}
53+
54+
return $value;
55+
}
56+
57+
private static function throwValueErrorIfAvailable(string $message): void
58+
{
59+
if (!class_exists(\ValueError::class)) {
60+
throw new \InvalidArgumentException($message);
61+
}
62+
63+
throw new \ValueError($message);
64+
}
65+
}

src/Php86/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Symfony Polyfill / Php86
2+
========================
3+
4+
This component provides features added to PHP 8.6 core:
5+
6+
- [`clamp`](https://wiki.php.net/rfc/clamp_v2)
7+
8+
More information can be found in the
9+
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
10+
11+
License
12+
=======
13+
14+
This library is released under the [MIT license](LICENSE).

src/Php86/bootstrap.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Polyfill\Php86 as p;
13+
14+
if (\PHP_VERSION_ID >= 80600) {
15+
return;
16+
}
17+
18+
if (!function_exists('clamp')) {
19+
/**
20+
* @template V
21+
* @template L
22+
* @template H
23+
*
24+
* @param V $value
25+
* @param L $min
26+
* @param H $max
27+
*
28+
* @return V|L|H
29+
*/
30+
function clamp($value, $min, $max) { return p\Php86::clamp($value, $min, $max); }
31+
}

src/Php86/composer.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "symfony/polyfill-php86",
3+
"type": "library",
4+
"description": "Symfony polyfill backporting some PHP 8.6+ features to lower PHP versions",
5+
"keywords": ["polyfill", "shim", "compatibility", "portable"],
6+
"homepage": "https://symfony.com",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Nicolas Grekas",
11+
"email": "p@tchwork.com"
12+
},
13+
{
14+
"name": "Symfony Community",
15+
"homepage": "https://symfony.com/contributors"
16+
}
17+
],
18+
"require": {
19+
"php": ">=7.2"
20+
},
21+
"autoload": {
22+
"psr-4": { "Symfony\\Polyfill\\Php86\\": "" },
23+
"files": [ "bootstrap.php" ]
24+
},
25+
"minimum-stability": "dev",
26+
"extra": {
27+
"thanks": {
28+
"name": "symfony/polyfill",
29+
"url": "https://github.com/symfony/polyfill"
30+
}
31+
}
32+
}

src/bootstrap.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,7 @@
4040
if (\PHP_VERSION_ID < 80500) {
4141
require __DIR__.'/Php85/bootstrap.php';
4242
}
43+
44+
if (\PHP_VERSION_ID < 80600) {
45+
require __DIR__.'/Php86/bootstrap.php';
46+
}

tests/Php86/Php86Test.php

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Polyfill\Tests\Php86;
13+
14+
use PHPUnit\Framework\TestCase;
15+
16+
/** @group php86 */
17+
class Php86Test extends TestCase
18+
{
19+
public function testClamp(): void
20+
{
21+
$this->assertSame(2, clamp(2, 1, 3));
22+
$this->assertSame(1, clamp(0, 1, 3));
23+
$this->assertSame(3, clamp(6, 1, 3));
24+
$this->assertSame(2, clamp(2, 1.3, 3.4));
25+
$this->assertSame(2.5, clamp(2.5, 1, 3));
26+
$this->assertSame(2.5, clamp(2.5, 1.3, 3.4));
27+
$this->assertSame(1.3, clamp(0, 1.3, 3.4));
28+
$this->assertSame(M_PI, clamp(M_PI, -INF, INF));
29+
$this->assertTrue(is_nan(clamp(NAN, 4, 6)));
30+
$this->assertSame('c', clamp('a', 'c', 'g'));
31+
$this->assertSame('d', clamp('d', 'c', 'g'));
32+
$this->assertSame('2025-08-15', clamp('2025-08-01', '2025-08-15', '2025-09-15'));
33+
$this->assertSame('2025-08-20', clamp('2025-08-20', '2025-08-15', '2025-09-15'));
34+
$this->assertSame('2025-08-15', clamp(new \DateTimeImmutable('2025-08-01'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d'));
35+
$this->assertSame('2025-08-20', clamp(new \DateTimeImmutable('2025-08-20'), new \DateTimeImmutable('2025-08-15'), new \DateTimeImmutable('2025-09-15'))->format('Y-m-d'));
36+
37+
$errorMessage = null;
38+
39+
try {
40+
clamp(4, NAN, 6);
41+
} catch (\ValueError $error) {
42+
$errorMessage = $error->getMessage();
43+
}
44+
45+
$this->assertSame('clamp(): Argument #2 ($min) cannot be NAN', $errorMessage);
46+
47+
$errorMessage = null;
48+
49+
try {
50+
clamp(7, 6, NAN);
51+
} catch (\ValueError $error) {
52+
$errorMessage = $error->getMessage();
53+
}
54+
55+
$this->assertSame('clamp(): Argument #3 ($max) cannot be NAN', $errorMessage);
56+
57+
$errorMessage = null;
58+
59+
try {
60+
clamp(1, 3, 2);
61+
} catch (\ValueError $error) {
62+
$errorMessage = $error->getMessage();
63+
}
64+
65+
$this->assertSame('clamp(): Argument #2 ($min) must be smaller than or equal to argument #3 ($max)', $errorMessage);
66+
}
67+
}

0 commit comments

Comments
 (0)