Build pipelines that gracefully abort or default when they hit missing data, without littering every step with `if ($x !== null)` checks. Three approaches — composeSafe, composeTypeSafe, and ifThen / always guards — each suited to a different shape of problem.
You’re walking data that might be partially missing. Nested property lookups, optional fields, fallback defaults. The imperative version is nested ternaries or a mound of if guards. You want a pipeline that just deals with null.
Best when “null anywhere” means “give up, answer is null”.
use PinkCrab\FunctionConstructors\GeneralFunctions as F;
$getAuthorName = F\composeSafe(
F\getProperty('book'), // might be null
F\getProperty('author'), // might be null
F\getProperty('name') // might be null
);
$order = ['book' => ['author' => ['name' => 'Ada']]];
echo $getAuthorName($order); // 'Ada'
$orderNoBook = ['book' => null];
var_dump($getAuthorName($orderNoBook)); // NULL — chain halted on bookNo inline null checks. One failing step short-circuits the whole chain.
When you want stronger assurance than “not null” — e.g. “every intermediate must still be a string”.
$buildSlug = F\composeTypeSafe(
'is_string',
'trim',
'strtolower',
fn($s) => str_replace(' ', '-', $s)
);
echo $buildSlug(' Hello World '); // 'hello-world'
var_dump($buildSlug(42)); // NULL — 42 isn't a string, chain aborts
var_dump($buildSlug(null)); // NULL — sameWhen you want the pipeline to continue, using a default when something’s missing.
$fallbackTo = fn($default) => F\ifElse(
fn($v) => $v !== null,
fn($v) => $v, // pass through if set
F\always($default) // default otherwise
);
$getUsername = F\compose(
F\pluckProperty('profile', 'displayName'),
$fallbackTo('anonymous')
);
echo $getUsername(['profile' => ['displayName' => 'Ada']]); // 'Ada'
echo $getUsername(['profile' => []]); // 'anonymous'
echo $getUsername([]); // 'anonymous'| You want… | Use |
|---|---|
| “Null anywhere → whole result is null” | composeSafe |
| “Null anywhere → abort with null, AND the type must stay consistent” | composeTypeSafe |
| “Null here → substitute a default, keep going” | ifThen / ifElse + always |
You can nest these freely. A typical shape: use composeSafe to walk a nested lookup, then ifElse at the end to turn the result (possibly null) into a sensible default:
$getTitle = F\compose(
F\composeSafe(
F\getProperty('book'),
F\getProperty('title')
),
F\ifElse(
fn($v) => $v !== null,
'strtoupper',
F\always('UNTITLED')
)
);
echo $getTitle(['book' => ['title' => 'abc']]); // 'ABC'
echo $getTitle(['book' => null]); // 'UNTITLED'Each step still describes one thing. No isset() ladder.