Potherca
11/14/2017 - 11:47 AM

Comparison of Callable and Closure type hint in PHP - see https://ideone.com/Vo9vpd or https://3v4l.org/jqMtg

Comparison of Callable and Closure type hint in PHP - see https://ideone.com/Vo9vpd or https://3v4l.org/jqMtg

================================================================================
(1) string :  'foo'

    callable : false
    __invoke : false
    closure  : false 

================================================================================
(2) string :  'trim'

    callable : true
    __invoke : false
    closure  : false 

================================================================================
(3) string :  '\\Potherca\\Example\\TypeHints\\Example::typeHintMissing'

    callable : true
    __invoke : false
    closure  : false 

================================================================================
(4) array :  array (0 => '\\Potherca\\Example\\TypeHints\\Example',1 => 'typeHintMissing',)

    callable : true
    __invoke : false
    closure  : false 

================================================================================
(5) array :  array (0 => Potherca\Example\TypeHints\Example::__set_state(array()),1 => 'typeHintMissing',)

    callable : true
    __invoke : false
    closure  : false 

================================================================================
(6) object :  Potherca\Example\TypeHints\Example::__set_state(array())

    callable : true
    __invoke : true
    closure  : false 

================================================================================
(7) object :  Closure::__set_state(array())

    callable : true
    __invoke : true
    closure  : true
<?php
/**
 * Output of this file can be seen "live" at https://ideone.com/Vo9vpd or https://3v4l.org/jqMtg
 */

namespace Potherca\Example\TypeHints;

class Example
{
    public static function typeHintMissing($subject)
    {
        return $subject;
    }

    public static function typeHintCallable(callable $subject)
    {
        return $subject;
    }

    public static function typeHintClosure(\Closure $subject)
    {
        return $subject;
    }

    public function __invoke($subject)
    {
        return $subject;
    }
}

$output = <<<'TXT'

================================================================================
(%d) %s :  %s

    callable : %s
    __invoke : %s
    closure  : %s 

TXT;

$example = new Example();

$callables = array(
    1 => 'foo',
    2 => 'trim',
    3 => '\Potherca\Example\TypeHints\Example::typeHintMissing',
    4 => array('\Potherca\Example\TypeHints\Example', 'typeHintMissing'),
    5 => array($example, 'typeHintMissing'),
    6 => $example,
    7 => function ($subject) {return $subject;},
);

array_walk($callables, function ($callable, $key) use ($output) {

    $is_callable = is_callable($callable);
    $is_invoke = method_exists($callable, '__invoke');
    $is_closure = $callable instanceof \Closure;

    if ($is_callable === true) {
        /** @noinspection VariableFunctionsUsageInspection */
        call_user_func($callable, 'foo');
        Example::typeHintCallable($callable);
    }

    if ($is_closure === true) {
        Example::typeHintClosure($callable);
    }

    if ($is_invoke === true) {
        $callable('foo');
    }

    vprintf($output, array(
        'key' => $key,
        'type' => gettype($callable),
        'value' => str_replace(array("\n", '  '), '', var_export($callable, true)),
        'is_callable' => var_export($is_callable, true),
        'is_invoke' => var_export($is_invoke, true),
        'is_closure' => var_export($is_closure, true),
    ));
});