Oihana PHP

callables

Table of Contents

Functions

chainCallables()  : callable|null
Chains multiple callables to be executed in sequence.
isCallable()  : bool
Checks whether a string can be resolved into a valid callable.
memoizeCallable()  : callable
Memoizes a callable's result (caches based on arguments).
middlewareCallable()  : callable
Wrap a callable with before/after middleware.
resolveCallable()  : callable|null
Resolves a string callable into an actual callable.
wrapCallable()  : callable
Wraps a callable to apply middleware/decorators before/after execution.

Functions

chainCallables()

Chains multiple callables to be executed in sequence.

chainCallables([array<string|int, mixed> $callables = [] ]) : callable|null

Creates a pipeline where each callable's output becomes the next callable's input. The first callable receives the arguments passed to the chain; subsequent callables receive only the result from the previous callable.

Returns null if the array is empty or if any callable cannot be resolved. Execution stops at the first unresolvable callable in the chain.

Parameters
$callables : array<string|int, mixed> = []

An array of callables to execute in sequence. Each can be a string, array, object, or Closure.

Tags
example
use function oihana\core\callables\chainCallables;

// Example 1: Data transformation pipeline
$pipe = chainCallables([
    'trim',
    'strtoupper',
    fn($str) => str_repeat($str, 2)
]);
echo $pipe('  hello  '); // "HELLOHELLO"

// Example 2: Mathematical operations
$calculate = chainCallables([
    fn($x) => $x * 2,
    fn($x) => $x + 10,
    fn($x) => sqrt($x)
]);
echo $calculate(5); // sqrt((5*2)+10) = sqrt(20) ≈ 4.47

// Example 3: With static methods
$pipe = chainCallables
([
    'MyClass::parse',
    'MyClass::validate',
    'MyClass::transform'
]);
$result = $pipe($input);

// Example 4: With object methods
$handler = new Handler();
$pipe = chainCallables
([
    [ $handler , 'preprocess'  ] ,
    [ $handler , 'process'     ] ,
    [ $handler , 'postprocess' ]
]);
$result = $pipe($data);
see
wrapCallable()

To add decorators around a callable

author

Marc Alcaraz (ekameleon)

since
1.0.7
Return values
callable|null

A new callable that executes the chain, or null if invalid

isCallable()

Checks whether a string can be resolved into a valid callable.

isCallable(string $callable) : bool

This is a convenience wrapper around resolveCallable() that returns a boolean instead of the callable itself. Useful for validation or conditional logic.

Supports the same callable formats as resolveCallable():

  • Fully qualified function names: 'oihana\core\normalize'
  • Static method notation: 'MyClass::method' or 'MyNamespace\MyClass::method'
Parameters
$callable : string

The callable as a string to check

Tags
see
resolveCallable()
example
use function oihana\core\callables\isCallable;

if (isCallable('oihana\core\normalize')) {
    // Safe to use the function
}

if (isCallable('MyClass::transform')) {
    // Safe to call the static method
}

if (!isCallable('nonexistent\function')) {
    // Handle missing function
}
author

Marc Alcaraz (ekameleon)

since
1.0.7
Return values
bool

True if the callable can be resolved, false otherwise

memoizeCallable()

Memoizes a callable's result (caches based on arguments).

memoizeCallable(callable $callable) : callable

Returns a new callable that caches results based on the arguments passed. Subsequent calls with the same arguments return the cached result instead of re-executing the original callable. This improves performance for expensive computations with repeated identical arguments.

Cache keys are generated by serializing arguments using serialize(). Works with scalar values, arrays, and objects that support serialization.

WARNING: The cache grows indefinitely. For long-running processes with many unique argument combinations, consider clearing the cache or using a size limit.

Parameters
$callable : callable

The original callable to memoize

Tags
example
use function oihana\core\callables\memoizeCallable;

// Example 1: Expensive computation
$expensive = function($n) {
    echo "Computing...";
    return $n * $n;
};

$memoized = memoizeCallable($expensive);
echo $memoized(5); // "Computing..." outputs 25
echo $memoized(5); // outputs 25 (cached, no "Computing...")
echo $memoized(6); // "Computing..." outputs 36 (different arg)

// Example 2: API call memoization
$fetchUser = memoizeCallable( function( $userId )
{
    return file_get_contents("https://api.example.com/users/{$userId}");
} ) ;

$user1 = $fetchUser(123); // Makes actual API call
$user2 = $fetchUser(123); // Returns cached result

// Example 3: Fibonacci with memoization
$fib = null;
$fib = memoizeCallable( function($n) use (&$fib)
{
    if ($n <= 1) return $n;
    return $fib($n - 1) + $fib($n - 2);
});
echo $fib(30); // Very fast due to memoization

// Example 4: With multiple arguments
$add = memoizeCallable(fn($a, $b) => $a + $b);
echo $add( 2 , 3 ) ; // 5
echo $add( 2 , 3 ) ; // 5 (cached)
echo $add( 3 , 2 ) ; // 5 (different cache key since args differ)
see
wrapCallable()

To apply custom decorators instead

author

Marc Alcaraz (ekameleon)

since
1.0.7
Return values
callable

A new callable with memoization enabled

middlewareCallable()

Wrap a callable with before/after middleware.

middlewareCallable(callable $callable[, callable|array<string|int, callable> $before = [] ][, callable|array<string|int, callable> $after = [] ]) : callable

This function allows decorating a callable with logic that runs before and/or after the original callable. Supports a single callable or an array of callables for both before and after.

  • before callables receive the original arguments.
  • after callables receive the original arguments + the result. If an after callback returns a non-null value, it overrides the result.
Parameters
$callable : callable

The main callable to wrap

$before : callable|array<string|int, callable> = []

Callable or array of callables to run before

$after : callable|array<string|int, callable> = []

Callable or array of callables to run after

Tags
example
use function oihana\core\callables\middlewareCallable;

$fn = fn(int $x): int => $x * 2;

// Single before and after callables
$wrapped = middlewareCallable(
    $fn,
    before: fn(int $x) => print("Before $x\n"),
    after:  fn(int $x, int $result) => print("After $result\n")
);

echo $wrapped(5); // Before 5, After 10, 10

// Multiple before/after callables
$wrapped2 = middlewareCallable
(
    $fn,
    before: [
        fn(int $x) => print("B1-$x\n"),
        fn(int $x) => print("B2-$x\n")
    ],
    after: [
        fn(int $x, int $r) => print("A1-$r\n"),
        fn(int $x, int $r) => print("A2-$r\n")
    ]
);

echo $wrapped2(3); // B1-3, B2-3, A1-6, A2-6, 6
author

Marc Alcaraz

since
1.0.7
Return values
callable

Wrapped callable with middleware applied

resolveCallable()

Resolves a string callable into an actual callable.

resolveCallable(string|array<string|int, mixed>|object|null $callable) : callable|null

This function attempts to convert various callable representations into actual PHP callables that can be invoked directly. It validates the existence of functions and methods before returning them, ensuring the returned callable is executable.

Supports multiple callable formats:

  • Fully qualified function names: 'oihana\core\normalize'
  • Static method notation: 'MyClass::method' or 'MyNamespace\MyClass::method'
  • Array callables: [$object, 'method'] or ['ClassName', 'method']
  • Invokable objects: Objects implementing __invoke method
  • Closure instances and callable objects

Returns null if the callable cannot be resolved (function/method does not exist or format is invalid).

Parameters
$callable : string|array<string|int, mixed>|object|null

The callable candidate to resolve. Can be:

  • A string containing a function or method name
  • An array with object/class and method name
  • An object instance with __invoke method
  • A Closure instance
  • null
Tags
example
use function oihana\core\callables\resolveCallable;

// Function by fully qualified name
$fn = resolveCallable('oihana\core\normalize');
if ($fn !== null)
{
    $result = $fn($value);
}

// Static method
$fn = resolveCallable('MyNamespace\MyClass::transform');
if ($fn !== null)
{
    $result = $fn($data);
}

// Array callable with object instance
$handler = new MyHandler();
$fn = resolveCallable([$handler, 'handle']);

// Invokable object
$fn = resolveCallable(new MyCallable());

// Non-existent function returns null
$fn = resolveCallable('nonexistent\function'); // null
$fn = resolveCallable('NonExistentClass::method'); // null
see
is_callable()

For direct callable validation without resolution

author

Marc Alcaraz (ekameleon)

since
1.0.7
Return values
callable|null

The resolved callable that can be executed, or null if the callable cannot be resolved or does not exist in the current runtime.

wrapCallable()

Wraps a callable to apply middleware/decorators before/after execution.

wrapCallable(callable $callable, callable $wrapper) : callable

This function allows you to decorate a callable with custom logic that executes before and/or after the original callable is invoked. The wrapper receives the original callable and its arguments, giving complete control over execution flow.

The wrapper callable receives:

  • First argument: The original callable to invoke
  • Remaining arguments: The arguments passed to the wrapped callable

The wrapper is responsible for calling the original callable and returning its result. This enables use cases like logging, timing, error handling, caching, etc.

Parameters
$callable : callable

The original callable to wrap

$wrapper : callable

A callable that receives the original callable and args. Signature: function($original, ...$args)

Tags
example
use function oihana\core\callables\wrapCallable;

// Example 1: Logging wrapper
$fn = fn($x) => $x * 2;
$logged = wrapCallable($fn, function($original, ...$args)
{
    echo "Calling with: " . json_encode($args);
    $result = $original(...$args);
    echo "Result: $result";
    return $result;
});
$logged(5); // Logs: Calling with: [5], Result: 10

// Example 2: Error handling wrapper
$wrapped = wrapCallable('json_decode', function( $original , ...$args )
{
    try
    {
        return $original(...$args) ;
    }
    catch (Throwable $e)
    {
        return null ;
    }
});

// Example 3: Timing wrapper
$timed = wrapCallable( $expensiveFn , function( $original , ...$args )
{
    $start    = microtime(true);
    $result   = $original(...$args);
    $duration = microtime(true) - $start;
    error_log( "Execution took {$duration}s" ) ;
    return $result;
});
see
chainCallables()

To combine multiple callables in sequence

author

Marc Alcaraz (ekameleon)

since
1.0.7
Return values
callable

A new wrapped callable that applies the wrapper logic


        
On this page

Search results