What does the keyword "callable" do in PHP - php

To be more exact, the "callable" used in function declaration arguments. like the one below.
function post($pattern, callable $handler) {
$this->routes['post'][$pattern] = $handler;
return $this;
}
How does it benefit us?
why and how do we use it?
Maybe this is very basic for you, however, I've tried searching for it and I was getting no answers. at least, nothing I could understand.
Hoping for a for-dummies answer. I'm new to coding... XD
Edit: Here's a link to where I copied the above piece of code from: link

The callable type allows us to pass a callback function to the function that is being called. That is, callback function parameters allow the function being called to dynamically call code that we specify in the callable function parameter. This is useful because it allows us to pass dynamic code to be executed to a function.
For example, one might want to call a function and the function accepts a callback function called log, which would log data in a custom way that you want.
I hope that makes sense. For details, see this link.

It's a type hinting which tells us this function accepts the parameter $handler as a function, see this example to clarify things:
function helloWorld()
{
echo 'Hello World!';
}
function handle(callable $fn)
{
$fn(); // We know the parameter is callable then we execute the function.
}
handle('helloWorld'); // Outputs: Hello World!
It's a very simple example, But I hope it helps you understand the idea.

Here is example use of using a callable as a parameter.
The wait_do_linebreak function below will sleep for a given time, then call a function with the tailing parameters given, and then echo a line break.
...$params packs the tailing parameters into an array called $params. Here it's being used to proxy arguments into the callables.
At the end of the examples you'll see a native function that takes a callable as a parameter.
<?php
function wait_do_linebreak($time, callable $something, ...$params)
{
sleep($time);
call_user_func_array($something, $params);
echo "\n";
}
function earth_greeting() {
echo 'hello earth';
}
class Echo_Two
{
public function __invoke($baz, $bat)
{
echo $baz, " ", $bat;
}
}
class Eat_Static
{
static function another()
{
echo 'Another example.';
}
}
class Foo
{
public function more()
{
echo 'And here is another one.';
}
}
wait_do_linebreak(0, 'earth_greeting');
$my_echo = function($str) {
echo $str;
};
wait_do_linebreak(0, $my_echo, 'hello');
wait_do_linebreak(0, function() {
echo "I'm on top of the world.";
});
wait_do_linebreak(0, new Echo_Two, 'The', 'Earth');
wait_do_linebreak(0, ['Eat_Static', 'another']);
wait_do_linebreak(0, [new Foo, 'more']);
$array = [
'jim',
'bones',
'spock'
];
$word_contains_o = function (string $str) {
return strpos($str, 'o') !== false;
};
print_r(array_filter($array, $word_contains_o));
Output:
hello earth
hello
I'm on top of the world.
The Earth
Another example.
And here is another one.
Array
(
[1] => bones
[2] => spock
)

A callable (callback) function is a function that is called inside another function or used as a parameter of another function
// An example callback function
function my_callback_function() {
echo 'hello world!';
}
// Type 1: Simple callback
call_user_func('my_callback_function');
There are some cases that your function is a template for other functions, in that case, you use parameters for the callable function.
for more information:
http://php.net/manual/en/language.types.callable.php

Callable
callable is a php data type. It simply means anything which can be called i.e. a function type. If this function is a closure, static/regular method or something else doesn't matter as long as we can call the function.
Example:
//php callable type
$callback = function() {
return "hello world!\n";
};
class MyClass {
static function myCallbackMethod() {
return "static method call \n";
}
public function cb()
{
return "method call \n";
}
public function __invoke() {
return "invoke \n";
}
}
$obj = new MyClass();
// Illustrative function
function soUseful (callable $callback) {
echo $callback();
}
soUseful($callback);
soUseful(array($obj, 'cb')); // syntax for making method callable
soUseful(array('MyClass', 'myCallbackMethod')); // syntax for making static method callable
soUseful($obj); // Object can be made callable via __invoke()
soUseful(fn() => "hi from closure \n"); // arrow fn
//Output
//hello world!
//method call
//static method call
//invoke
//hi from closure

Callable is a data-type.
note: You can always check whether your variables are of type "callable" by using the built-in is_callable function, giving your variable's handler as its argument.
The "callable" keyword seen in the code, is used for a "Type declaration", also known as "type hint" in PHP 5. this is used to specify which type of argument or parameter your functions or methods accept. this is done by simply putting the "type hint" or "Type declaration" (i.e. the name of the type, like in this case, "callable") before the parameter names.
Whenever using "type hints" or "Type declarations" for your function declarations (i.e. when you've specified which types are allowed/accepted), and you're calling them giving parameters of data-types other than those specified as acceptable, an error is generated.
note: also, class names can be used if you would like to make your function require > an object instantiated from a specific class < for its respective parameter
-
References:
php manual > type-declaration
php manual > callable type
-
I'm new to coding so please correct my mistakes :)

Use callable to require a callback function as an argument
We use it with argument of function it will strict to to pass callable( closure static/regular function ) when we calling the function
Example 1 not Passing a Callable in function call :
$myfuntion = function(callable $sum){
};
// when calling myfuntion i passed integer
$myfuntion(123);
// it will not allow us to do this
Example 2 Passing Callable in function call :
$sum = function($arr){
echo array_sum($arr);
};
$myfuntion = function(callable $sum){
// do something
};
$myfuntion($sum);
// Sum is a callable function now it will work absolutely fine
Proper Example :
$sum = function( ...$args){
echo array_sum($args);
};
$myfun = function(callable $sum){
$sum(1,2,3,4,5);
};
$myfun($sum);

Related

PHP method callback

How to pass method callback as a parameter to another method? All the examples I've seen use functions, but not methods. What I've tried is:
call_user_func($this, 'method_name', [$param1, $param2,...]);
Also is there another, more elegant way, like just passing $this->method_name as a parameter?
I know I could add the callback as:
function () use ($param1, $param2,...) {
return $this->method_name($param1, $param2);
}
But I would like to omit the closure part.
You could also use [$obj, 'method'] as an callback, bind to an object.
class A {
public $b = 'test';
public function callback() {
echo $this->b;
}
}
$a = new A();
$f = [$a, 'callback'];
$f();

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

I noticed that I can use either of Closure or Callable 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 use Closure and when to use Callable or do they serve the same purpose?
The difference is, that a Closure must be an anonymous function, where callable also can be a normal function.
You can see/test this with the example below and you will see that you will get an error for the first one:
function callFunc1(Closure $closure) {
$closure();
}
function callFunc2(Callable $callback) {
$callback();
}
function xy() {
echo 'Hello, World!';
}
callFunc1("xy"); // Catchable fatal error: Argument 1 passed to callFunc1() must be an instance of Closure, string given
callFunc2("xy"); // Hello, World!
So if you only want to type hint anonymous function use: Closure and if you want also to allow normal functions use callable as type hint.
The main difference between them is that a closure is a class and callable a type.
The callable type accepts anything that can be called:
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
); // all true
Where a closure will only accept an anonymous function. Note that in PHP version 7.1 you can convert functions to a closure like so:
Closure::fromCallable('functionName').
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 a closure over callable?
Strictness because a closure is an object that has some additional methods: call(), bind() and bindto(). 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 a closure. Otherwise just use a normal callback. 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: The closure class cannot be extended as its final.
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,

Binding an anonymous function to an existing function in PHP

Is there a way to bind an existing function to an anonymous one in php? Something like
$my_func = strip_tags();
Or must I half-redefine it, as a sort of anonymous wrapper, with the proper arguments and return value?
I tried googling this, but I suppose I didn't correctly suss the proper search phrase, as I didn't find results on the first page.
Edit I'm making a sort of function pipeline(?) where I can pass data and functions, and I want to pass functions as variables. I would like to keep the syntax the same and be able to use $output = $function($data) without having to write a bunch of anonymous wrappings for native functions. Also I would like to avoid using call_user_func so I don't have to re-write my existing code.
Simple.
$my_func = 'strip_tags';
$output = $my_func($data);
You can bind the function by it's name. Have a look at the callable Interface from php
Code from the manual mentioned above
<?php
// An example callback function
function my_callback_function() {
echo 'hello world!';
}
// An example callback method
class MyClass {
static function myCallbackMethod() {
echo 'Hello World!';
}
}
// Type 1: Simple callback
call_user_func('my_callback_function');
// Type 2: Static class method call
call_user_func(array('MyClass', 'myCallbackMethod'));
// Type 3: Object method call
$obj = new MyClass();
call_user_func(array($obj, 'myCallbackMethod'));
// Type 4: Static class method call (As of PHP 5.2.3)
call_user_func('MyClass::myCallbackMethod');
// Type 5: Relative static class method call (As of PHP 5.3.0)
class A {
public static function who() {
echo "A\n";
}
}
class B extends A {
public static function who() {
echo "B\n";
}
}
call_user_func(array('B', 'parent::who')); // A
?>

How can I use a callback function which is stored as a class member in PHP?

Consider the following code, which is a scheme of storing a callback function as a member, and then using it:
class MyClass {
function __construct($callback) {
$this->callback = $callback;
}
function makeCall() {
return $this->callback();
}
}
function myFunc() {
return 'myFunc was here';
}
$o = new MyClass(myFunc);
echo $o->makeCall();
I would expect myFunc was here to be echoed, but instead I get:
Call to undefined method MyClass::callback()
Can anyone explain what's wrong here, and what I can do in order to get the desired behaviour?
In case it matters, I am using PHP 5.3.13.
You can change your makeCall method to this:
function makeCall() {
$func = $this->callback;
return $func();
}
Pass it as a string and call it by call_user_func.
class MyClass {
function __construct($callback) {
$this->callback = $callback;
}
function makeCall() {
return call_user_func($this->callback);
}
}
function myFunc() {
return 'myFunc was here';
}
$o = new MyClass("myFunc");
echo $o->makeCall();
One important thing about PHP is that it recognises the type of a symbol with the syntax rather than the contents of it, so you need to state explicitly what you refer to.
In many languages you just write:
myVariable
myFunction
myConstant
myClass
myClass.myStaticMethod
myObject.myMethod
And the parser/compiler knows what each of the symbols means, because it's aware of what they refer to simply by knowing what's assigned to them.
In PHP, however, you need to use the syntax to let the parser know what "symbol namespace" you refer to, so normally you write:
$myVariable
myFunction()
myConstant
new myClass
myClass::myStaticMethod()
$myObject->method()
However, as you can see these are calls rather than references. To pass a reference to a function, class or method in PHP, combined string and array syntax is used:
'myFunction'
array('myClass', 'myStaticMethod')
array($myObject, 'myMethod')
In your case, you need to use 'myFunc' in place of myFunc to let PHP know that you're passing a reference to a function and not retrieving the value the myFunc constant.
Another ramification is that when you write $myObject->callback(), PHP assumes callback is a method because of the parentheses and it does not attempt to loop up a property.
To achieve the expected result, you need to either store a copy of/reference to the property callback in a local variable and use the following syntax:
$callback = $this->callback;
return $callback();
which identifies it as a closure, because of the dollar sign and the parentheses; or call it with the call_user_func function:
call_user_func($this->callback);
which, on the other hand, is a built-in function that expects callback.

Something like a callback delegate function in php

I would like to implement something similar to a c# delegate method in PHP. A quick word to explain what I'm trying to do overall: I am trying to implement some asynchronous functionality. Basically, some resource-intensive calls that get queued, cached and dispatched when the underlying system gets around to it. When the asynchronous call finally receives a response I would like a callback event to be raised.
I am having some problems coming up with a mechanism to do callbacks in PHP. I have come up with a method that works for now but I am unhappy with it. Basically, it involves passing a reference to the object and the name of the method on it that will serve as the callback (taking the response as an argument) and then use eval to call the method when need be. This is sub-optimal for a variety of reasons, is there a better way of doing this that anyone knows of?
(Apart from the observer pattern) you can also use call_user_func() or call_user_func_array().
If you pass an array(obj, methodname) as first parameter it will invoked as $obj->methodname().
<?php
class Foo {
public function bar($x) {
echo $x;
}
}
function xyz($cb) {
$value = rand(1,100);
call_user_func($cb, $value);
}
$foo = new Foo;
xyz( array($foo, 'bar') );
?>
How do you feel about using the Observer pattern? If not, you can implement a true callback this way:
// This function uses a callback function.
function doIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
print 'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Displays: Data is: this is my data
I was wondering if we could use __invoke magic method to create "kind of" first class function and thus implement a callback
Sound something like that, for PHP 5.3
interface Callback
{
public function __invoke();
}
class MyCallback implements Callback
{
private function sayHello () { echo "Hello"; }
public function __invoke () { $this->sayHello(); }
}
class MySecondCallback implements Callback
{
private function sayThere () { echo "World"; }
public function __invoke () { $this->sayThere(); }
}
class WhatToPrint
{
protected $callbacks = array();
public function register (Callback $callback)
{
$this->callbacks[] = $callback;
return $this;
}
public function saySomething ()
{
foreach ($this->callbacks as $callback) $callback();
}
}
$first_callback = new MyCallback;
$second_callback = new MySecondCallback;
$wrapper = new WhatToPrint;
$wrapper->register($first_callback)->register($second_callback)->saySomething();
Will print HelloWorld
Hope it'll help ;)
But I'd prefer the Controller pattern with SPL for such a feature.

Categories