Oihana PHP

callables

Table of Contents

Classes

CallableType
Defines the possible types of a callable reference.

Functions

chainCallables()  : callable|null
Chains multiple callables to be executed in sequence.
countCallableParam()  : int
Returns the number of parameters of a given callable.
getCallableType()  : string|false
Determines the type of a callable reference and optionally normalizes it.
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

countCallableParam()

Returns the number of parameters of a given callable.

countCallableParam(callable|string|array<string|int, mixed>|object $callable[, bool $useCache = true ]) : int

This function accepts any PHP callable (Closure, invokable object, array [object/class, method], string function name, or static method string) and returns the number of parameters it declares.

Optionally, a cache can be used to avoid repeated reflection lookups for the same callable, which is useful when the callable is repeatedly inspected (e.g., in loops or recursive functions).

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

The callable to inspect.

$useCache : bool = true

Whether to cache the computed parameter count. Default true.

Tags
throws
InvalidArgumentException

If the callable cannot be resolved or is unsupported.

throws
ReflectionException

If the callable cannot be reflected (rare).

example

Basic usage with a named function

function testFunction($a, $b, $c) }
echo countCallableParam('testFunction'); // 3
example

With a Closure

$fn = function($x, $y) };
echo countCallableParam($fn); // 2
example

With an invokable object

class MyCallable { public function __invoke($a, $b, $c, $d) } }
$obj = new MyCallable();
echo countCallableParam($obj); // 4
example

With a static method

class MyClass { public static function myMethod($x, $y) } }
echo countCallableParam('MyClass::myMethod'); // 2
example

With an object method

class MyClass { public function myMethod($x, $y, $z) } }
$obj = new MyClass();
echo countCallableParam([$obj, 'myMethod']); // 3
author

Marc Alcaraz (ekameleon)

since
1.0.8
Return values
int

The number of parameters declared by the callable.

getCallableType()

Determines the type of a callable reference and optionally normalizes it.

getCallableType(mixed $callable[, bool $strict = true ][, callable|null &$norm = null ]) : string|false

This function analyzes a PHP callable and returns its standardized type according to the constants defined in CallableType. It can also normalize the callable form for consistent usage throughout your application.

Callable Types and Normalization

Callable Normalization Returned Type
function (...) {...} function (...) {...} 'closure'
$object (with __invoke) $object 'invocable'
"function" "function" 'function'
"Class::method" ["Class", "method"] 'static'
["Class", "parent::method"] ["ParentClass", "method"] 'static'
["Class", "self::method"] ["Class", "method"] 'static'
["Class", "method"] ["Class", "method"] 'static'
[$object, "parent::method"] [$object, "parent::method"] 'object'
[$object, "self::method"] [$object, "method"] 'object'
[$object, "method"] [$object, "method"] 'object'
Other recognized callable Same as input 'unknown'
Non-callable Same as input false

Strict Mode

When the $strict parameter is set to true, additional checks are performed using the Reflection API:

  • For callable strings like "Class::method" or arrays like ["Class", "method"], the method must be declared as static.
  • For callable arrays like [$object, "method"], the method must be an instance method (non-static).

In non-strict mode ($strict = false), these checks are skipped and the type is determined solely by the callable's structure.

Usage Examples

// Closure
$type = getCallableType(fn() => 42, false, $norm);
// Returns: 'closure', $norm = the closure itself

// Named function
$type = getCallableType('strlen', false, $norm);
// Returns: 'function', $norm = 'strlen'

// Static method (string form)
$type = getCallableType('MyClass::myMethod', false, $norm);
// Returns: 'static', $norm = ['MyClass', 'myMethod']

// Static method (array form)
$type = getCallableType(['MyClass', 'myMethod'], false, $norm);
// Returns: 'static', $norm = ['MyClass', 'myMethod']

// Instance method
$obj = new MyClass();
$type = getCallableType([$obj, 'myMethod'], false, $norm);
// Returns: 'object', $norm = [$obj, 'myMethod']

// Invocable object
$invocable = new class {
    public function __invoke() { return 'hello'; }
};
$type = getCallableType($invocable, false, $norm);
// Returns: 'invocable', $norm = $invocable

// Non-callable
$type = getCallableType(123, false, $norm);
// Returns: false, $norm = 123
Parameters
$callable : mixed

The callable reference to analyze.

$strict : bool = true

When true, uses Reflection to verify that static/instance methods are used correctly. Defaults to true.

$norm : callable|null = null

Receives the normalized form of the callable (passed by reference). If the callable is invalid, contains the original value.

Tags
see
CallableType

For the list of type constants returned by this function

see
is_callable()

For PHP's native callable verification function

see
ReflectionMethod

For the Reflection API used in strict mode

author

Marc Alcaraz (ekameleon)

since
1.0.7
Return values
string|false

One of CallableType::CLOSURE, CallableType::INVOCABLE, CallableType::FUNCTION, CallableType::STATIC, CallableType::OBJECT, CallableType::UNKNOWN, or false if not a callable.

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