php - Type hinting – Difference between `Closure` and `Callable`

223

I noticed that I can use either ofClosure orCallable as type hint if we expected some callback function to run. For example:

function callFunc1(Closure $closure) {
    $closure();
}

function callFunc2(Callable $callback) {
    $callback();
}

$function = function() {
    echo 'Hello, World!';
};

callFunc1($function); // Hello, World!
callFunc2($function); // Hello, World!

Question

What's the difference here? In other words when to useClosure and when to useCallable or do they serve the same purpose?

788

Answer

Solution:

The main difference between them is that a is a class and a type.

Thecallable type accepts anything that can be called:

var_dump(
  is_callable('functionName'),
  is_callable([$myClass, 'methodName']),
  is_callable(function(){})
); // all true

Where aclosure will only accept an anonymous function. Note that in PHP version 7.1 you can convert functions to a closure like so: .


Example:

namespace foo{
  class bar{
    private $baz = 10;

    function myCallable(callable $cb){$cb()}
    function myClosure(\Closure $cb){$cb()} // type hint must refer to global namespace
  }

  function func(){}
  $cb = function(){};
  $fb = new bar;

  $fb->myCallable(function(){});
  $fb->myCallable($cb);
  $fb->myCallable('func');

  $fb->myClosure(function(){});
  $fb->myClosure($cb);
  $fb->myClosure(\Closure::fromCallable('func'));
  $fb->myClosure('func'); # TypeError
}

So why use aclosure overcallable?

Strictness because aclosure is an object that has some additional methods: , and . They allow you to use a function declared outside of a class and execute it as if it was inside a class:

$inject = function($i){return $this->baz * $i;};
$cb1 = \Closure::bind($inject, $fb);
$cb2 = $inject->bindTo($fb);

echo $cb1->call($fb, 2); // 20
echo $cb2(3);            // 30

You would not like to call methods on a normal function as that will raise fatal errors. So in order to circumvent that you would have to write something like:

if($cb instanceof \Closure){}

To do this check every time is pointless. So if you want to use those methods state that the argument is aclosure. Otherwise just use a normalcallback. This way; An error is raised on function call instead of your code causing it making it much easier to diagnose.

On a side note: Theclosure class cannot be extended as its final.

397

Answer

Solution:

It's worth mentioning that this won't work for PHP versions 5.3.21 to 5.3.29.

In any of those versions you will get an output like:

Hello, World! Catchable fatal error: Argument 1 passed to callFunc2() must be an instance of > Callable, instance of Closure given, called in /in/kqeYD on line 16 and defined in /in/kqeYD on line 7

Process exited with code 255.

One can try that out using https://3v4l.org/kqeYD#v5321

Best regards,

People are also looking for solutions to the problem: Laravel PHP: Do not display 'blank' checkbox data in view

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.