Callables

Phuture\Coherence\Callables

class Callables extends StaticClass

Comprehensive callable manipulation utility class for higher-order function composition.

This utility class provides a complete toolkit for working with functions and callables, including function composition, currying, memoization, partial application, and execution control mechanisms such as throttling, debouncing, retrying, and rate limiting.

Key features:

  • Composition: Combine functions into pipelines using compose() and pipe()
  • Currying & Partial Application: Transform multi-argument functions with curry() and partial()
  • Memoization: Cache expensive function results with memoize() and a configurable TTL
  • Execution Control: Throttle, debounce, defer, and rate-limit function calls
  • Error Handling: Wrap functions with catch() and retry() for resilient execution
  • Lifecycle Hooks: Attach before() and after() hooks to any callable
  • Introspection: Inspect callables with arity(), isClosure(), isStatic(), and more
  • Transformation: Flip argument order, limit argument count with unary() and binary()

Constants

CACHE_TTL

const CACHE_TTL = 60 * 1000

Default time-to-live for cached function results in milliseconds.

This constant defines the default cache duration for the memoize() method when no custom TTL is specified. The value is in milliseconds to provide precise timing control.

Value: 60,000 milliseconds = 60 seconds = 1 minute

EXECUTION_DELAY

const EXECUTION_DELAY = 500

Default delay in milliseconds between function executions.

This constant is used as the default delay for both throttle() and retry() methods when no custom delay is specified.

MAX_ATTEMPTS

const MAX_ATTEMPTS = 10

Default maximum number of retry attempts for the retry() method.

This constant defines how many times the retry mechanism will attempt to execute a function before giving up and throwing the last exception.

Methods

after()

public static function after(callable $callback, callable $after): Closure

Creates a function that executes a hook after the main function.

This method returns a closure that first executes the main function, then executes an "after" function with the result and the original arguments. The result of the after function is ignored - the main function's result is always returned.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$logEnd = fn($result, $operation) => echo "Finished $operation. Result: " . json_encode($result) . "\n";
 4$processData = fn($data) => array_map(fn($item) => $item * 2, $data);
 5
 6$loggedProcess = Callables::after($processData, $logEnd);
 7$result = $loggedProcess([1, 2, 3]);
 8// Outputs: Finished processing. Result: [2,4,6]
 9// Returns [2, 4, 6]
10
11// Cleanup after operations
12$cleanup = fn($result, $tempFile) => unlink($tempFile);
13$processWithTemp = fn($tempFile) => processFile($tempFile);
14$cleanProcess = Callables::after($processWithTemp, $cleanup);
15
16// Notifications
17$notifyUser = fn($result, $userId) => sendNotification($userId, 'Task completed!');
18$task = fn($userId) => performLongTask($userId);
19$taskWithNotification = Callables::after($task, $notifyUser);
Parameter Type Description
$callback callable The main function to execute
$after callable The function to execute after the main function (receives result, then args)

Returns Closure — A function that executes the main function, then the after hook

See also

  • \Phuture\Coherence\Callables::before()
  • \Phuture\Coherence\Callables::wrap()

apply()

public static function apply(callable $callback, array $args): mixed

Calls a function with arguments from an array.

This method executes a callable using an array of arguments. The array elements are spread out as individual arguments to the function. This is useful when you have arguments collected in an array that need to be passed to a function.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$format = fn($name, $age, $city) => "$name is $age from $city";
 4$args = ['Alice', 30, 'New York'];
 5$result = Callables::apply($format, $args);
 6// Returns "Alice is 30 from New York"
 7
 8// Database query example
 9$insert = fn($table, $data, $timestamp) => db_insert($table, $data, $timestamp);
10$queryArgs = ['users', ['name' => 'John'], date('Y-m-d')];
11Callables::apply($insert, $queryArgs);
Parameter Type Description
$callback callable The function to call
$args array The array of arguments to spread into the function

Returns mixed — The return value of the called function

See also

  • \Phuture\Coherence\Callables::call()
  • \Phuture\Coherence\Callables::spread()

before()

public static function before(callable $callback, callable $before): Closure

Creates a function that executes a hook before the main function.

This method returns a closure that first executes a "before" function with the provided arguments, then executes the main function with the same arguments. The before function's return value is ignored - only the main function's result is returned.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$logStart = fn($operation, $data) => echo "Starting $operation with " . json_encode($data) . "\n";
 4$processData = fn($operation, $data) => array_map(fn($item) => $item * 2, $data);
 5
 6$loggedProcess = Callables::before($processData, $logStart);
 7$result = $loggedProcess('doubling', [1, 2, 3]);
 8// Outputs: Starting doubling with [1,2,3]
 9// Returns [2, 4, 6]
10
11// Validation before processing
12$validate = fn($data) => {
13    if (empty($data)) throw new \InvalidArgumentException('Data cannot be empty');
14};
15$safeProcess = Callables::before($processData, $validate);
16
17// Setting up context
18$setupDatabase = fn($query) => db()->beginTransaction();
19$runQuery = fn($query) => db()->query($query);
20$transactionalQuery = Callables::before($runQuery, $setupDatabase);
Parameter Type Description
$callback callable The main function to execute
$before callable The function to execute before the main function

Returns Closure — A function that executes the before hook, then the main function

See also

  • \Phuture\Coherence\Callables::after()
  • \Phuture\Coherence\Callables::wrap()

binary()

public static function binary(callable $callback): Closure

Creates a function that only uses the first two arguments.

This method returns a closure that ignores all arguments except the first two and passes them to the original function. Useful for creating binary functions from multi-argument functions or ensuring only two arguments are processed.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$concat = fn($a, $b, $c, $d) => $a . $b . $c . $d;
 4$firstTwo = Callables::binary($concat);
 5
 6$result1 = $firstTwo('Hello', ' ', 'World', '!'); // Returns "Hello " (ignores extra args)
 7$result2 = $firstTwo('A', 'B'); // Returns "AB"
 8
 9// Mathematical operations
10$power = fn($base, $exp, $mod) => pow($base, $exp);
11$simplePower = Callables::binary($power);
12$result3 = $simplePower(2, 3, 1000); // Returns 8 (ignores modulus)
Parameter Type Description
$callback callable The function to call with only the first two arguments

Returns Closure — A function that uses only the first two arguments

See also

  • \Phuture\Coherence\Callables::unary()

bind()

public static function bind(Closure $closure, ?object $class): Closure

Binds a closure to a specific object context.

This method changes the $this context of a closure to point to a specific object. This allows the closure to access the object's properties and methods as if it were a method of that class.

Example:

 1use Phuture\Coherence\Callables;
 2
 3class User {
 4    public $name = 'John';
 5    public $age = 30;
 6}
 7
 8$closure = fn() => return "Name: {$this->name}, Age: {$this->age}";
 9$user = new User();
10
11$bound = Callables::bind($closure, $user);
12$result = $bound(); // Returns "Name: John, Age: 30"
13
14// Without binding would cause an error
15$result2 = $closure(); // Error: $this is not available
Parameter Type Description
$closure Closure The closure to bind to an object
$class `object null`

Returns Closure — A new closure bound to the specified object

call()

public static function call(callable $callback, mixed ...$args): mixed

Calls a function with the provided arguments.

This method executes a callable with a variable number of arguments. It's a simple wrapper that makes function calls more consistent and allows for better function composition patterns.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$add = fn($a, $b) => $a + $b;
 4$result = Callables::call($add, 5, 3); // Returns 8
 5
 6// Useful with other Callables methods
 7$operations = [
 8    fn($n) => $n * 2,
 9    fn($n) => $n + 1,
10    fn($n) => $n ** 2
11];
12$results = array_map(fn($op) => Callables::call($op, 5), $operations);
Parameter Type Description
$callback callable The function to call
...$args mixed The arguments to pass to the function

Returns mixed — The return value of the called function

See also

  • \Phuture\Coherence\Callables::apply()

catch()

public static function catch(callable $callback, callable $handler): Closure

Creates a function that catches exceptions and handles them gracefully.

This method returns a closure that executes the original function and, if it throws an exception, calls a handler function instead. The handler receives both the exception and the original arguments.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$divide = fn($a, $b) => $a / $b;
 4$safeDivide = Callables::catch($divide, function ($e, $a, $b) {
 5    if ($e instanceof \DivisionByZeroError) {
 6        return "Cannot divide by zero";
 7    }
 8    return "Error: " . $e->getMessage();
 9});
10
11$result1 = $safeDivide(10, 2); // Returns 5
12$result2 = $safeDivide(10, 0); // Returns "Cannot divide by zero"
13
14// File operations with error handling
15$readFile = fn($path) => file_get_contents($path);
16$safeRead = Callables::catch($readFile, function ($e, $path) {
17    return "Could not read file: $path";
18});
Parameter Type Description
$callback callable The function to execute with error handling
$handler callable The function to call on exception (receives exception, then args)

Returns Closure — A function that catches exceptions and handles them

See also

  • \Phuture\Coherence\Callables::safe()

compose()

public static function compose(callable ...$callback): Closure

Creates a function that applies multiple functions in right-to-left order.

This method creates a closure that applies functions from last to first. The output of each function becomes the input to the next function. This is useful for creating data transformation pipelines.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$add1 = fn($x) => $x + 1;
 4$double = fn($x) => $x * 2;
 5
 6$composed = Callables::compose($add1, $double);
 7$result = $composed(5);
 8// Returns 11 (5 * 2 + 1)
 9
10// Multiple functions
11$pipeline = Callables::compose(
12    fn($x) => $x + 1,
13    fn($x) => $x * 2,
14    fn($x) => $x - 3
15);
16$result = $pipeline(10);
17// Returns 19 ((10 - 3) * 2 + 1)
Parameter Type Description
...$callback callable The functions to compose, applied right-to-left

Returns Closure — A new closure that applies all functions in composition

See also

  • \Phuture\Coherence\Callables::pipe()

constant()

public static function constant(mixed $value): Closure

Creates a function that always returns the same value.

This method returns a closure that ignores any arguments and always returns the same constant value. Useful for default values, testing, or when you need a function that provides a fixed response.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$always42 = Callables::constant(42);
 4$result1 = $always42(); // Returns 42
 5$result2 = $always42(1, 2, 3); // Still returns 42
 6
 7// Default values
 8$getDefaultId = Callables::constant('default-123');
 9$userId = $userId ?? $getDefaultId();
10
11// Testing with mock data
12$mockApi = Callables::constant(['status' => 'success', 'data' => [1, 2, 3]]);
13$response = $mockApi($request);
14
15// Configuration constants
16$getTimeout = Callables::constant(30);
17$timeout = $getTimeout();
Parameter Type Description
$value mixed The value to always return

Returns Closure — A function that always returns the specified value

See also

  • \Phuture\Coherence\Callables::identity()

curry()

public static function curry(callable $callback, ?int $arity = null): Closure

Creates a curried version of a function.

This method transforms a function into a series of functions that each accept a single argument. When all required arguments have been provided, the original function is executed. This enables partial application and function composition.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$add = fn($a, $b, $c) => $a + $b + $c;
 4$curried = Callables::curry($add);
 5
 6// Provide arguments one at a time
 7$add1 = $curried(1);
 8$add1and2 = $add1(2);
 9$result = $add1and2(3); // Returns 6 (1 + 2 + 3)
10
11// Or provide multiple arguments at once
12$result2 = $curried(10, 20)(5); // Returns 35 (10 + 20 + 5)
13
14// Custom arity (number of arguments expected)
15$customCurry = Callables::curry($add, 2); // Expects only 2 arguments
16$result3 = $customCurry(5)(10); // Returns 15 (ignores the third parameter)
Parameter Type Description
$callback callable The function to curry
$arity `int null`

Returns Closure — A curried version of the function

Throws

  • \Phuture\Coherence\Exception\RuntimeException — When unable to determine function arity automatically

See also

  • Reflector::arity()

defer()

public static function defer(callable $callback, int $milliseconds = self::EXECUTION_DELAY): Closure

Creates a function that delays execution before calling the callback.

This method returns a closure that waits for the specified number of milliseconds before executing the original function. Useful for debouncing, creating delays in animations, or implementing retry logic with backoff.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$sendEmail = fn($to, $message) => mail($to, 'Subject', $message);
 4
 5// Delay email sending by 2 seconds
 6$delayedEmail = Callables::defer($sendEmail, 2000);
 7$result = $delayedEmail('[email protected]', 'Hello!'); // Sends after 2 seconds
 8
 9// Debouncing user input
10$search = fn($query) => performApiSearch($query);
11$debouncedSearch = Callables::defer($search, 500);
12
13// If user types quickly, only the last search executes
14$debouncedSearch('a');
15$debouncedSearch('ap');
16$debouncedSearch('app'); // Only this one executes after 500ms
17
18// Simulated slow operation for testing
19$slowOperation = Callables::defer(fn() => 'Done', 1000);
Parameter Type Description
$callback callable The function to execute after delay
$milliseconds int The delay in milliseconds before execution (default: EXECUTION_DELAY)

Returns Closure — A function that delays execution before calling the callback

See also

  • \Phuture\Coherence\Callables::EXECUTION_DELAY

flip()

public static function flip(callable $callback): Closure

Creates a function that reverses the order of arguments.

This method returns a closure that calls the original function with its arguments in reverse order. Useful for adapting functions that expect arguments in a different order than what you have available.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$divide = fn($a, $b) => $a / $b;
 4$reciprocalDivide = Callables::flip($divide);
 5
 6$result1 = $divide(10, 2); // Returns 5 (10 ÷ 2)
 7$result2 = $reciprocalDivide(10, 2); // Returns 0.2 (2 ÷ 10)
 8
 9// String formatting with reversed arguments
10$format = fn($template, $value) => sprintf($template, $value);
11$reverseFormat = Callables::flip($format);
12$result3 = $reverseFormat('Hello %s', 'World'); // "World Hello"
Parameter Type Description
$callback callable The function to call with reversed arguments

Returns Closure — A function that reverses argument order

identity()

public static function identity(): Closure

Creates a function that returns its input unchanged.

This method returns a closure that simply returns whatever value it receives. It's the identity function in mathematics - f(x) = x. Useful as a default transformation or when you need a function that does nothing.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$identity = Callables::identity();
 4$result1 = $identity(5); // Returns 5
 5$result2 = $identity('hello'); // Returns 'hello'
 6$result3 = $identity([1, 2, 3]); // Returns [1, 2, 3]
 7
 8// As default transformation
 9$transform = $transformFunction ?? Callables::identity();
10$data = array_map($transform, $items);
11
12// In pipelines where you might want to skip a step
13$process = $shouldProcess ? $actualProcessor : Callables::identity();

Returns Closure — A function that returns its input unchanged

See also

  • \Phuture\Coherence\Callables::constant()

if()

public static function if(callable $condition, callable $then, ?callable $else): Closure

Creates a function that chooses between two callbacks based on a condition function.

This method returns a closure that evaluates a condition function with the provided arguments. If the condition returns true, it executes the "then" callback. If false, it executes the "else" callback. All three functions receive the same arguments.

Example:

1use Phuture\Coherence\Callables;
2
3$isEven = fn($n) => $n % 2 === 0;
4$sayEven = fn($n) => "$n is even";
5$sayOdd = fn($n) => "$n is odd";
6
7$checkNumber = Callables::ifElse($isEven, $sayEven, $sayOdd);
8$result1 = $checkNumber(4); // Returns "4 is even"
9$result2 = $checkNumber(5); // Returns "5 is odd"
Parameter Type Description
$condition callable The function that determines which callback to execute
$then callable The function to execute when the condition is true
$else `callable null`

Returns Closure — A function that chooses between two callbacks based on a condition

See also

  • \Phuture\Coherence\Callables::when()
  • \Phuture\Coherence\Callables::unless()

isCallable()

public static function isCallable(mixed $value): bool

Checks if a value can be called as a function.

This method determines if the given value is callable, meaning it can be invoked as a function. This includes functions, methods, closures, and objects with an __invoke method.

Example:

1use Phuture\Coherence\Callables;
2
3Callables::isCallable('strlen'); // true
4Callables::isCallable([new DateTime(), 'format']); // true
5Callables::isCallable(fn($x) => $x); // true
6Callables::isCallable('not_a_function'); // false
Parameter Type Description
$value mixed The value to check if it's callable

Returns bool — True if the value is callable, false otherwise

See also

  • \Phuture\Coherence\Callables::isClosure()
  • \Phuture\Coherence\Callables::isFunction()

isClosure()

public static function isClosure(mixed $value): bool

Checks if a value is a closure.

This method determines if the given value is an instance of a Closure, which is an anonymous function that can be stored in a variable and passed as an argument.

Example:

1use Phuture\Coherence\Callables;
2
3Callables::isClosure(fn($x) => $x * 2); // true
4Callables::isClosure(function() { return 'hi'; }); // true
5Callables::isClosure('strlen'); // false
6Callables::isClosure([DateTime::class, 'format']); // false
Parameter Type Description
$value mixed The value to check if it's a closure

Returns bool — True if the value is a closure, false otherwise

See also

  • \Phuture\Coherence\Callables::isCallable()

isFunction()

public static function isFunction(mixed $value): bool

Checks if a value represents an existing PHP function.

This method determines if the given value is a string that matches the name of an existing PHP function. This includes built-in functions and user-defined functions, but not methods or class methods.

Example:

1use Phuture\Coherence\Callables;
2
3Callables::isFunction('strlen'); // true (built-in)
4Callables::isFunction('my_custom_func'); // true (if defined)
5Callables::isFunction('DateTime::format'); // false (method)
6Callables::isFunction(['Class', 'method']); // false (array)
7Callables::isFunction(fn($x) => $x); // false (closure)
Parameter Type Description
$value mixed The value to check if it's a function name

Returns bool — True if the value is a valid function name, false otherwise

See also

  • \Phuture\Coherence\Callables::isMethod()
  • \Phuture\Coherence\Callables::isCallable()

isInvokable()

public static function isInvokable(mixed $value): bool

Checks if an object can be invoked as a function.

This method determines if the given value is an object that has an __invoke method, which allows the object to be called like a function. This is useful for objects that need to behave like callables.

Example:

 1use Phuture\Coherence\Callables;
 2
 3class Invoker {
 4    public function __invoke($x) {
 5        return $x * 2;
 6    }
 7}
 8
 9$invoker = new Invoker();
10Callables::isInvokable($invoker); // true (has __invoke)
11Callables::isInvokable(new DateTime()); // false (no __invoke)
12Callables::isInvokable('strlen'); // false (string)
13Callables::isInvokable(fn($x) => $x); // false (closure)
Parameter Type Description
$value mixed The value to check if it's an invokable object

Returns bool — True if the value is an object with __invoke method, false otherwise

See also

  • \Phuture\Coherence\Callables::isCallable()

isMethod()

public static function isMethod(mixed $value): bool

Checks if a value represents a method callable.

This method determines if the given value is an array that represents a method call. A method callable must have exactly two elements: the first is the object or class name, and the second is the method name as a string.

Example:

1use Phuture\Coherence\Callables;
2
3$object = new DateTime();
4Callables::isMethod([$object, 'format']); // true (instance method)
5Callables::isMethod([DateTime::class, 'format']); // true (static method)
6Callables::isMethod(['stdClass', 'format']); // false (method doesn't exist)
7Callables::isMethod(['function_name']); // false (wrong format)
8Callables::isMethod('strlen'); // false (not an array)
Parameter Type Description
$value mixed The value to check if it's a method callable

Returns bool — True if the value is a valid method callable, false otherwise

See also

  • \Phuture\Coherence\Callables::isFunction()
  • \Phuture\Coherence\Callables::isCallable()

isStatic()

public static function isStatic(callable $callback): bool

Checks if a callable is static.

This method determines if the given callable represents a static method call. A static callable is one that doesn't require an object instance, such as [Class::class, 'method'] or 'Class::method'.

Example:

1use Phuture\Coherence\Callables;
2
3Callables::isStatic([DateTime::class, 'format']); // true (static method)
4Callables::isStatic('DateTime::format'); // true (static string)
5Callables::isStatic([new DateTime(), 'format']); // false (instance method)
6Callables::isStatic('strlen'); // true (function)
7Callables::isStatic(fn($x) => $x); // false (closure)
Parameter Type Description
$callback callable The callable to check if it's static

Returns bool — True if the callable is static, false otherwise

memoize()

public static function memoize(callable $callback, ?int $ttl = self::CACHE_TTL): Closure

Creates a memoized version of a function with optional time-to-live.

This method returns a closure that caches the results of function calls for a specified time period. The cache key is based on the serialized arguments, so identical argument sets will return cached results.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$slowOperation = fn($x) => {
 4    sleep(1); // Simulate slow operation
 5    return $x * 2;
 6};
 7
 8// Use default TTL from CACHE_TTL constant
 9$memoized = Callables::memoize($slowOperation);
10$result1 = $memoized(5); // Takes 1 second, returns 10
11$result2 = $memoized(5); // Instant, returns 10 (from cache)
12
13// Custom TTL of 10 seconds
14$customCache = Callables::memoize($slowOperation, 10);
15$result3 = $customCache(5); // Returns 10, expires after 10 seconds
16
17// Different arguments create separate cache entries
18$result4 = $memoized(10); // Takes 1 second, returns 20
19
20// Null TTL means cache never expires during runtime
21$permanentCache = Callables::memoize($slowOperation, null);
22$result5 = $permanentCache(5); // Cached until script ends
Parameter Type Description
$callback callable The function to memoize
$ttl `int null`

Returns Closure — A memoized version of the function with TTL support

See also

  • \Phuture\Coherence\Callables::CACHE_TTL

negate()

public static function negate(callable $callback): Closure

Creates a function that returns the logical negation of the original result.

This method returns a closure that executes the original function and returns the opposite boolean value. Useful for inverting conditions, validation logic, or boolean predicates.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$isEven = fn($n) => $n % 2 === 0;
 4$isOdd = Callables::negate($isEven);
 5
 6$result1 = $isOdd(4); // Returns false (4 is even)
 7$result2 = $isOdd(5); // Returns true (5 is odd)
 8
 9// Validation filtering
10$isValid = fn($email) => filter_var($email, FILTER_VALIDATE_EMAIL);
11$isInvalid = Callables::negate($isValid);
12$invalidEmails = array_filter($emails, $isInvalid);
Parameter Type Description
$callback callable The function to negate the result of

Returns Closure — A function that returns the opposite boolean value

once()

public static function once(callable $callback): Closure

Creates a function that only executes once per unique callback.

This method returns a closure that executes the original function only the first time it's called. Subsequent calls will return null without executing the function again. The tracking is based on the callback itself, not the arguments, so each unique function can only run once.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$setupDatabase = fn() => echo "Setting up database\n";
 4$onceSetup = Callables::once($setupDatabase);
 5
 6$result1 = $onceSetup(); // Outputs "Setting up database", returns null
 7$result2 = $onceSetup(); // Returns null (no execution)
 8$result3 = $onceSetup(); // Still returns null (no execution)
 9
10// Different callback, can execute once
11$anotherSetup = fn() => echo "Another setup\n";
12$onceAnother = Callables::once($anotherSetup);
13$result4 = $onceAnother(); // Outputs "Another setup", returns null
14$result5 = $onceAnother(); // Returns null (no execution)
Parameter Type Description
$callback callable The function that should only run once

Returns Closure — A function that executes only once per callback

partial()

public static function partial(callable $callback, mixed ...$args): Closure

Creates a new function with some arguments pre-filled from the left.

This method returns a closure that has some of the original function's arguments already set. When called, it prepends the pre-filled arguments to any new arguments provided.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$subtract = fn($a, $b, $c) => $a - $b - $c;
 4$partialSub = Callables::partial($subtract, 10);
 5$result = $partialSub(2, 3);
 6// Returns 5 (10 - 2 - 3)
 7
 8// Multiple pre-filled arguments
 9$add = fn($a, $b, $c, $d) => $a + $b + $c + $d;
10$partialAdd = Callables::partial($add, 1, 2);
11$result = $partialAdd(3, 4);
12// Returns 10 (1 + 2 + 3 + 4)
13
14// String formatting
15$format = fn($prefix, $name, $suffix) => "$prefix$name$suffix";
16$greet = Callables::partial($format, "Hello, ");
17$result = $greet("World", "!");
18// Returns "Hello, World!"
Parameter Type Description
$callback callable The function to partially apply
...$args mixed The arguments to pre-fill from the left

Returns Closure — A new function with left arguments pre-filled

See also

  • \Phuture\Coherence\Callables::partialRight()
  • \Phuture\Coherence\Callables::curry()

partialRight()

public static function partialRight(callable $callback, mixed ...$args): Closure

Creates a new function with some arguments pre-filled from the right.

This method returns a closure that has some of the original function's arguments already set. When called, it appends the pre-filled arguments to any new arguments provided.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$subtract = fn($a, $b, $c) => $a - $b - $c;
 4$partialSub = Callables::partialRight($subtract, 3);
 5$result = $partialSub(10, 2);
 6// Returns 5 (10 - 2 - 3)
 7
 8// Multiple pre-filled arguments
 9$add = fn($a, $b, $c, $d) => $a + $b + $c + $d;
10$partialAdd = Callables::partialRight($add, 3, 4);
11$result = $partialAdd(1, 2);
12// Returns 10 (1 + 2 + 3 + 4)
13
14// Division with fixed divisor
15$divide = fn($numerator, $denominator) => $numerator / $denominator;
16$halve = Callables::partialRight($divide, 2);
17$result = $halve(20);
18// Returns 10
19
20$quarter = Callables::partialRight($divide, 4);
21$result = $quarter(20);
22// Returns 5
Parameter Type Description
$callback callable The function to partially apply
...$args mixed The arguments to pre-fill from the right

Returns Closure — A new function with right arguments pre-filled

See also

  • \Phuture\Coherence\Callables::partial()
  • \Phuture\Coherence\Callables::curry()

passthrough()

public static function passthrough(callable $callback, mixed $value): mixed

Executes a function with a value but returns the value unchanged.

This method is like the simple version of tap() - it immediately executes a function with a value and returns that same value. It's useful when you want to do something with a value right now but keep using the original value.

The main difference from tap() is:

  • tap(): gives you a new function to use later
  • passthrough(): does the action right now

Example:

 1use Phuture\Coherence\Callables;
 2
 3$save = fn($data) => file_put_contents('log.txt', $data);
 4$data = "Important information";
 5
 6// Save the data but keep using it
 7$result = Callables::passthrough($data, $save);
 8// $result is still "Important information" (data was saved)
 9
10// Debugging without breaking the flow
11$debug = fn($value) => echo "Current value: $value\n";
12$name = Callables::passthrough("John", $debug);
13// Outputs: Current value: John
14// $name is still "John"
15
16// Same thing with tap() would be:
17$name = Callables::tap($debug)("John");
Parameter Type Description
$callback callable The function to execute with the value
$value mixed The value to pass to the function

Returns mixed — The original value unchanged

See also

  • \Phuture\Coherence\Callables::tap()

pipe()

public static function pipe(callable ...$callback): Closure

Creates a function that applies multiple functions in left-to-right order.

This method creates a closure that applies functions from first to last. The output of each function becomes the input to the next function. This is useful for creating processing pipelines where order matters.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$add1 = fn($x) => $x + 1;
 4$double = fn($x) => $x * 2;
 5
 6$piped = Callables::pipe($add1, $double);
 7$result = $piped(5);
 8// Returns 12 ((5 + 1) * 2)
 9
10// Multiple functions
11$pipeline = Callables::pipe(
12    fn($x) => $x + 1,
13    fn($x) => $x * 2,
14    fn($x) => $x - 3
15);
16$result = $pipeline(10);
17// Returns 19 (((10 + 1) * 2) - 3)
Parameter Type Description
...$callback callable The functions to pipe, applied left-to-right

Returns Closure — A new closure that applies all functions in sequence

See also

  • \Phuture\Coherence\Callables::compose()

rateLimit()

public static function rateLimit(callable $callback, int $maxAttempts = self::MAX_ATTEMPTS, int $milliseconds = self::EXECUTION_DELAY): Closure

Creates a function that limits the number of calls within a time period.

This method returns a closure that tracks how many times it's been called within a specified time period. If the limit is exceeded, it throws an exception. Different from throttle() which just skips execution when rate-limited.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$apiCall = fn($endpoint) => json_decode(file_get_contents($endpoint));
 4
 5// Maximum 10 calls per minute
 6$limitedApi = Callables::rateLimit($apiCall, 10, 60);
 7
 8$result1 = $limitedApi('https://api.example.com/data'); // Executes
 9// After 10 calls within 60 seconds:
10$result11 = $limitedApi('https://api.example.com/data'); // Throws RuntimeException
11
12// Rate limiting per user
13$userApiCalls = [];
14$rateLimitPerUser = function($userId, $endpoint) use ($apiCall, &$userApiCalls) {
15    $key = "user_$userId";
16    $limiter = $userApiCalls[$key] ?? Callables::rateLimit($apiCall, 5, 60);
17    $userApiCalls[$key] = $limiter;
18    return $limiter($endpoint);
19};
Parameter Type Description
$callback callable The function to rate-limit
$maxAttempts int Maximum number of allowed calls within the time period, defaults to MAX_ATTEMPTS
$milliseconds int Delay between calls in milliseconds, defaults to EXECUTION_DELAY

Returns Closure — A rate-limited version of the function

Throws

  • \Phuture\Coherence\Exception\RuntimeException — When the rate limit is exceeded

See also

  • \Phuture\Coherence\Callables::MAX_ATTEMPTS
  • \Phuture\Coherence\Callables::EXECUTION_DELAY

retry()

public static function retry(callable $callback, int $maxAttempts = self::MAX_ATTEMPTS, int $milliseconds = self::EXECUTION_DELAY): Closure

Creates a function that retries execution on failure.

This method returns a closure that attempts to execute the original function multiple times if it throws an exception. Between attempts, it waits for the specified delay. If all attempts fail, it throws the last exception.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$unreliableApi = fn($id) => {
 4    static $failCount = 0;
 5    $failCount++;
 6    if ($failCount <= 2) {
 7        throw new \Exception("API failed");
 8    }
 9    return "Data for $id";
10};
11
12$reliableApi = Callables::retry($unreliableApi, 3, 1000);
13$result = $reliableApi(123); // Succeeds after 2 retries, returns "Data for 123"
14
15// Use default values (10 max attempts, 500ms delay)
16$defaultRetry = Callables::retry($unreliableApi);
17
18// Fast retry with no delay
19$fastRetry = Callables::retry($unreliableApi, 5, 0);
Parameter Type Description
$callback callable The function to retry on failure
$maxAttempts int Maximum number of attempts, defaults to MAX_ATTEMPTS
$milliseconds int Delay between attempts in milliseconds, defaults to EXECUTION_DELAY

Returns Closure — A retry-enabled version of the function

See also

  • \Phuture\Coherence\Callables::MAX_ATTEMPTS
  • \Phuture\Coherence\Callables::EXECUTION_DELAY

safe()

public static function safe(callable $callback): Closure

Creates a function that never throws exceptions.

This method returns a closure that always returns a two-element array: [exception, result]. If the original function succeeds, the exception is null and the result contains the return value. If it fails, the exception object is returned and the result is null.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$divide = fn($a, $b) => $a / $b;
 4$safeDivide = Callables::safe($divide);
 5
 6$result1 = $safeDivide(10, 2);
 7// Returns [null, 5]
 8
 9$result2 = $safeDivide(10, 0);
10// Returns [DivisionByZeroError, null]
11
12// Processing results safely
13$parseJson = fn($str) => json_decode($str, true);
14$safeParse = Callables::safe($parseJson);
15
16[$error, $data] = $safeParse('{"valid": "json"}');
17if ($error === null) {
18    echo "Parsed: " . json_encode($data);
19} else {
20    echo "JSON error: " . $error->getMessage();
21}
Parameter Type Description
$callback callable The function to make exception-safe

Returns Closure — A function that returns [exception, result] instead of throwing

See also

  • \Phuture\Coherence\Callables::catch()

spread()

public static function spread(callable $callback): Closure

Creates a function that accepts an array and spreads it as arguments.

This method returns a closure that takes an array of arguments and spreads them into individual arguments for the original function. Useful for working with functions that expect individual arguments when you have them collected in an array.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$add = fn($a, $b, $c) => $a + $b + $c;
 4$addFromArray = Callables::spread($add);
 5
 6$numbers = [1, 2, 3];
 7$result1 = $addFromArray($numbers); // Returns 6 (1 + 2 + 3)
 8
 9// Database query parameters
10$query = fn($table, $where, $orderBy) => "SELECT * FROM $table WHERE $where ORDER BY $orderBy";
11$buildQuery = Callables::spread($query);
12$params = ['users', 'active = 1', 'created_at DESC'];
13$result2 = $buildQuery($params);
Parameter Type Description
$callback callable The function to call with spread arguments

Returns Closure — A function that accepts an array and spreads it

See also

  • \Phuture\Coherence\Callables::apply()

tap()

public static function tap(callable $callback): Closure

Creates a function that lets you "tap" into a value without changing it.

This method returns a closure that executes a function with a value but always returns the original value unchanged. Think of it like peeking at the value - you can look at it or do something with it, but the value stays the same and continues on its way.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$logger = fn($message) => echo "Log: $message\n";
 4$tapLogger = Callables::tap($logger);
 5
 6$result = $tapLogger("Hello World");
 7// Outputs: Log: Hello World
 8// $result contains "Hello World"
 9
10// Debugging in chains
11$process = fn($data) => $data * 2;
12$debug = fn($value) => echo "Processing: $value\n";
13
14$pipeline = Callables::pipe(
15    $process,
16    Callables::tap($debug),
17    $process
18);
19$result = $pipeline(5); // Logs "Processing: 10", returns 20
Parameter Type Description
$callback callable The function to execute with the value

Returns Closure — A function that executes the function but returns the original value

See also

  • \Phuture\Coherence\Callables::passthrough()

throttle()

public static function throttle(callable $callback, int $milliseconds = self::EXECUTION_DELAY): Closure

Creates a function that limits execution frequency to a minimum interval.

This method returns a closure that executes the original function only if enough time has passed since the last execution with the same arguments.

The milliseconds parameter specifies the required minimum interval and must always be provided.

It's useful for rate-limiting operations like API calls, animations, or preventing excessive resource usage.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$saveToDatabase = fn($data) => {
 4    echo "Saving: " . json_encode($data) . "\n";
 5    return true;
 6};
 7
 8$throttled = Callables::throttle($saveToDatabase, 1000); // 1 second required
 9
10$result1 = $throttled(['id' => 1]); // Executes, returns true
11$result2 = $throttled(['id' => 2]); // Returns null (only 500ms passed)
12usleep(600000); // Wait 600ms (total 1100ms)
13$result3 = $throttled(['id' => 3]); // Executes again, returns true
14
15// Different argument sets have separate timers
16$result4 = $throttled(['key' => 'A']); // Executes, separate 1s timer for 'A'
17$result5 = $throttled(['key' => 'A']); // Returns null (too soon for 'A')
18$result6 = $throttled(['key' => 'B']); // Executes, separate 1s timer for 'B'
19
20// Common throttle intervals:
21$slowApi = Callables::throttle($apiCall, 5000); // 5 seconds
22$uiUpdate = Callables::throttle($refreshUI, 100); // 100ms for smooth UI
Parameter Type Description
$callback callable The function to rate-limit
$milliseconds int Minimum time between executions in milliseconds, defaults to Callables::EXECUTION_DELAY

Returns Closure — A throttled version of the function

See also

  • \Phuture\Coherence\Callables::EXECUTION_DELAY

time()

public static function time(callable $callback, mixed ...$args): array

Measures the execution time of a function.

This method executes a callback and measures how long it takes to run. It returns an array containing both the function's result and the execution time in milliseconds. Useful for performance testing and optimization.

Example:

1use Phuture\Coherence\Callables;
2
3$slowFunction = fn($n) => {
4    usleep(100000); // Sleep for 100ms
5    return $n * 2;
6};
7
8$result = Callables::time($slowFunction);
9// Returns ['result' => 10, 'time' => ~100.5]
Parameter Type Description
$callback callable The function to time
...$args mixed The arguments to pass to the function

Returns array — An array with 'result' (function output) and 'time' (milliseconds)

toCallable()

public static function toCallable(Closure $callback): callable|array|string

Converts a closure to its underlying callable representation.

This method extracts the actual callable from a closure. If the closure wraps a method call, it returns an array with the object and method name. For simple closures, it returns the closure itself.

Example:

 1use Phuture\Coherence\Callables;
 2
 3// Simple closure
 4$closure = fn($x) => $x * 2;
 5$result = Callables::toCallable($closure);
 6// Returns the closure itself
 7
 8// Method closure
 9$object = new DateTime();
10$methodClosure = fn(...$args) => $object->format(...$args);
11$result = Callables::toCallable($methodClosure);
12// Returns [$object, 'format']
Parameter Type Description
$callback Closure The closure to convert to callable

Returns callable|array|string — The underlying callable, either as callable or array

See also

  • \Phuture\Coherence\Callables::toClosure()

toClosure()

public static function toClosure(callable $callback): Closure

Converts any callable to a closure.

This method creates a closure from any callable value, including functions, methods, and invokable objects. This is useful when you need a consistent closure type for function parameters or variable assignment.

Example:

 1use Phuture\Coherence\Callables;
 2
 3// Function to closure
 4$closure = Callables::toClosure('strlen');
 5$result = $closure('hello'); // Returns 5
 6
 7// Method to closure
 8$object = new DateTime();
 9$closure = Callables::toClosure([$object, 'format']);
10$result = $closure('Y-m-d'); // Returns current date
11
12// Static method to closure
13$closure = Callables::toClosure([DateTime::class, 'createFromFormat']);
14$date = $closure('Y-m-d', '2023-01-01');
Parameter Type Description
$callback callable The callable to convert to a closure

Returns Closure — The closure version of the callable

See also

  • \Phuture\Coherence\Callables::toCallable()

toString()

public static function toString(callable $callback): string

Converts a callable to a readable string representation.

This method creates a string that shows what the callable is, which can be useful for debugging or logging. The format depends on the callable type:

  • Functions: shows the function name
  • Methods: shows "Class::method"
  • Closures: shows "Closure"
  • Invokable objects: shows "Class::__invoke"

Example:

1use Phuture\Coherence\Callables;
2
3$str = Callables::toString('strlen'); // 'strlen'
4$str = Callables::toString([DateTime::class, 'format']); // 'DateTime::format'
5$str = Callables::toString(fn($x) => $x * 2); // 'Closure'
Parameter Type Description
$callback callable The callable to convert to string

Returns string — The readable string representation of the callable

unary()

public static function unary(callable $callback): Closure

Creates a function that only uses the first argument.

This method returns a closure that ignores all arguments except the first one and passes it to the original function. Useful for creating unary functions from multi-argument functions or ensuring only one argument is processed.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$add = fn($a, $b) => $a + $b;
 4$firstArg = Callables::unary($add);
 5
 6$result1 = $firstArg(5, 10, 15); // Returns 5 (ignores extra args)
 7$result2 = $firstArg(100); // Returns 100
 8
 9// Array processing
10$getFirst = fn($array) => $array[0];
11$extractFirst = Callables::unary($getFirst);
12$result3 = $extractFirst([1, 2, 3], [4, 5], [6, 7]); // Returns 1
Parameter Type Description
$callback callable The function to call with only the first argument

Returns Closure — A function that uses only the first argument

See also

  • \Phuture\Coherence\Callables::binary()

unless()

public static function unless(callable $callback, bool $condition): Closure

Creates a conditional function that executes only when a condition is false.

This method is the opposite of when() - it returns a new function that will execute your callback only when the condition is false. If the condition is true, it returns the first argument or null without executing the callback.

Example:

1use Phuture\Coherence\Callables;
2
3$logWhenNotProduction = Callables::unless(fn($msg) => error_log($msg), $isProduction);
4$logWhenNotProduction('Debug message'); // Only logs if not in production
Parameter Type Description
$callback callable The function to execute when condition is false
$condition bool The condition to check before executing the callback

Returns Closure — Returns a new function that conditionally executes the callback

See also

  • \Phuture\Coherence\Callables::when()

when()

public static function when(callable $callback, bool $condition): Closure

Creates a conditional function that executes a callback only when a condition is true.

This method returns a new function that will check a condition before executing your callback. If the condition is true, it runs the callback with the provided arguments. If false, it returns the first argument or null.

Example:

1use Phuture\Coherence\Callables;
2
3$logWhenDebug = Callables::when(fn($msg) => error_log($msg), $debugMode);
4$logWhenDebug('Debug message'); // Only logs if $debugMode is true
Parameter Type Description
$callback callable The function to execute when condition is true
$condition bool The condition to check before executing the callback

Returns Closure — Returns a new function that conditionally executes the callback

See also

  • \Phuture\Coherence\Callables::unless()

wrap()

public static function wrap(callable $callback, ?callable $before = null, ?callable $after = null): Closure

Creates a function with optional before and after hooks.

This method combines before() and after() into one convenient wrapper. It executes an optional "before" function, then the main function, then an optional "after" function. All three functions receive the same arguments, and the after function also receives the main function's result.

Example:

 1use Phuture\Coherence\Callables;
 2
 3$before = fn($data) => echo "Processing " . count($data) . " items\n";
 4$process = fn($data) => array_map(fn($x) => $x * 2, $data);
 5$after = fn($result, $original) => echo "Processed " . count($result) . " results\n";
 6
 7$wrapped = Callables::wrap($process, $before, $after);
 8$result = $wrapped([1, 2, 3, 4]);
 9// Outputs: Processing 4 items
10//         Processed 4 results
11// Returns [2, 4, 6, 8]
12
13// Only before hook
14$withBefore = Callables::wrap($process, $before);
15
16// Only after hook
17$withAfter = Callables::wrap($process, null, $after);
18
19// Database transaction wrapper
20$beginTransaction = fn() => db()->beginTransaction();
21$commit = fn($result) => db()->commit();
22$rollback = fn($error) => db()->rollback();
23
24$transactional = Callables::wrap($query, $beginTransaction, $commit);
Parameter Type Description
$callback callable The main function to wrap
$before `callable null`
$after `callable null`

Returns Closure — A function that wraps the main function with optional hooks

See also

  • \Phuture\Coherence\Callables::before()
  • \Phuture\Coherence\Callables::after()

delay()

private static function delay(int $milliseconds): void

Suspends execution for the given number of milliseconds.

Whole seconds are slept separately from the remaining microseconds so that the microsecond count handed to usleep() always stays below UINT_MAX. Passing the delay straight to usleep() overflows for delays beyond roughly 71 minutes, which PHP 8.6 reports as a ValueError. Delays of zero or less return immediately.

Parameter Type Description
$milliseconds int The number of milliseconds to sleep