Skip to content

Commit cd0b18e

Browse files
phananclaude
andcommitted
Add when and unless for single-branch conditional transforms
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 63aaefd commit cd0b18e

7 files changed

Lines changed: 182 additions & 0 deletions

File tree

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@
122122
"src/Functional/True.php",
123123
"src/Functional/Truthy.php",
124124
"src/Functional/Unique.php",
125+
"src/Functional/Unless.php",
125126
"src/Functional/ValueToKey.php",
127+
"src/Functional/When.php",
126128
"src/Functional/With.php",
127129
"src/Functional/Zip.php",
128130
"src/Functional/ZipAll.php"

docs/functional-php.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,40 @@ Applies a callback to each element in the collection and collects the return val
935935

936936
# Conditional functions
937937

938+
## when()
939+
940+
``mixed when(mixed $value, callable|mixed $if, callable $then)``
941+
Apply `$then` to the value if the condition is truthy, otherwise return the value unchanged. `$if` can be a callable (evaluated with the value) or a value (used directly as the condition).
942+
943+
```php
944+
use function Functional\when;
945+
946+
// With a callable condition
947+
when('foo', 'is_string', fn ($v) => strtoupper($v)); // 'FOO'
948+
when([1, 2], 'is_string', fn ($v) => strtoupper($v)); // [1, 2]
949+
950+
// With a value condition
951+
when($input, $isProduction, fn ($v) => htmlspecialchars($v));
952+
```
953+
954+
## unless()
955+
956+
``mixed unless(mixed $value, callable|mixed $if, callable $then)``
957+
Apply `$then` to the value if the condition is falsy, otherwise return the value unchanged. The inverse of `when()`. `$if` can be a callable or a value.
958+
959+
```php
960+
use function Functional\unless;
961+
962+
// With a callable condition
963+
unless(null, fn ($v) => $v !== null, fn () => 'default'); // 'default'
964+
unless('hello', fn ($v) => $v !== null, fn () => 'default'); // 'hello'
965+
966+
// With a value condition
967+
unless($input, $isProduction, fn ($v) => $v . ' [debug]');
968+
```
969+
970+
_See also `if_else()`, which requires both branches._
971+
938972
## if_else()
939973

940974
``callable if_else(callable $if, callable $then, callable $else)``

src/Functional/Functional.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,11 +493,21 @@ final class Functional
493493
*/
494494
const unique = '\Functional\unique';
495495

496+
/**
497+
* @see \Functional\unless
498+
*/
499+
const unless = '\Functional\unless';
500+
496501
/**
497502
* @see \Functional\value_to_key
498503
*/
499504
const value_to_key = '\Functional\value_to_key';
500505

506+
/**
507+
* @see \Functional\when
508+
*/
509+
const when = '\Functional\when';
510+
501511
/**
502512
* @see \Functional\with
503513
*/

src/Functional/Unless.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/**
4+
* @package Functional-php
5+
* @author Lars Strojny <lstrojny@php.net>
6+
* @copyright 2011-2021 Lars Strojny
7+
* @license https://opensource.org/licenses/MIT MIT
8+
* @link https://github.com/lstrojny/functional-php
9+
*/
10+
11+
namespace Functional;
12+
13+
/**
14+
* Apply $then to the value if the condition is falsy, otherwise return the value unchanged.
15+
*
16+
* $if can be a callable (evaluated with the value) or a value (used directly).
17+
*
18+
* @param mixed $value
19+
* @param callable|mixed $if the condition function or value
20+
* @param callable $then function to call if condition is false
21+
*
22+
* @return mixed
23+
* @no-named-arguments
24+
*/
25+
function unless($value, $if, callable $then)
26+
{
27+
$condition = \is_callable($if) ? $if($value) : $if;
28+
29+
return $condition ? $value : $then($value);
30+
}

src/Functional/When.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
/**
4+
* @package Functional-php
5+
* @author Lars Strojny <lstrojny@php.net>
6+
* @copyright 2011-2021 Lars Strojny
7+
* @license https://opensource.org/licenses/MIT MIT
8+
* @link https://github.com/lstrojny/functional-php
9+
*/
10+
11+
namespace Functional;
12+
13+
/**
14+
* Apply $then to the value if the condition is truthy, otherwise return the value unchanged.
15+
*
16+
* $if can be a callable (evaluated with the value) or a value (used directly).
17+
*
18+
* @param mixed $value
19+
* @param callable|mixed $if the condition function or value
20+
* @param callable $then function to call if condition is true
21+
*
22+
* @return mixed
23+
* @no-named-arguments
24+
*/
25+
function when($value, $if, callable $then)
26+
{
27+
$condition = \is_callable($if) ? $if($value) : $if;
28+
29+
return $condition ? $then($value) : $value;
30+
}

tests/Functional/UnlessTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/**
4+
* @package Functional-php
5+
* @author Lars Strojny <lstrojny@php.net>
6+
* @copyright 2011-2021 Lars Strojny
7+
* @license https://opensource.org/licenses/MIT MIT
8+
* @link https://github.com/lstrojny/functional-php
9+
*/
10+
11+
namespace Functional\Tests;
12+
13+
use function Functional\unless;
14+
use function Functional\equal;
15+
use function Functional\const_function;
16+
17+
class UnlessTest extends AbstractTestCase
18+
{
19+
public function testUnlessCallableConditionIsTrue(): void
20+
{
21+
self::assertEquals('foo', unless('foo', equal('foo'), const_function('bar')));
22+
}
23+
24+
public function testUnlessCallableConditionIsFalse(): void
25+
{
26+
self::assertEquals('bar', unless('qux', equal('foo'), const_function('bar')));
27+
}
28+
29+
public function testUnlessValueConditionIsTruthy(): void
30+
{
31+
self::assertEquals('anything', unless('anything', true, const_function('bar')));
32+
}
33+
34+
public function testUnlessValueConditionIsFalsy(): void
35+
{
36+
self::assertEquals('bar', unless('anything', false, const_function('bar')));
37+
}
38+
}

tests/Functional/WhenTest.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/**
4+
* @package Functional-php
5+
* @author Lars Strojny <lstrojny@php.net>
6+
* @copyright 2011-2021 Lars Strojny
7+
* @license https://opensource.org/licenses/MIT MIT
8+
* @link https://github.com/lstrojny/functional-php
9+
*/
10+
11+
namespace Functional\Tests;
12+
13+
use function Functional\when;
14+
use function Functional\equal;
15+
use function Functional\const_function;
16+
17+
class WhenTest extends AbstractTestCase
18+
{
19+
public function testWhenCallableConditionIsTrue(): void
20+
{
21+
self::assertEquals('bar', when('foo', equal('foo'), const_function('bar')));
22+
}
23+
24+
public function testWhenCallableConditionIsFalse(): void
25+
{
26+
self::assertEquals('qux', when('qux', equal('foo'), const_function('bar')));
27+
}
28+
29+
public function testWhenValueConditionIsTruthy(): void
30+
{
31+
self::assertEquals('bar', when('anything', true, const_function('bar')));
32+
}
33+
34+
public function testWhenValueConditionIsFalsy(): void
35+
{
36+
self::assertEquals('anything', when('anything', false, const_function('bar')));
37+
}
38+
}

0 commit comments

Comments
 (0)