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 |