How to use class methods as callbacks - php

I have a class with methods that I want to use as callbacks.
How can I pass them as arguments?
Class MyClass {
public function myMethod() {
// How should these be called?
$this->processSomething(this->myCallback);
$this->processSomething(self::myStaticCallback);
}
private function processSomething(callable $callback) {
// Process something...
$callback();
}
private function myCallback() {
// Do something...
}
private static function myStaticCallback() {
// Do something...
}
}

Check the callable manual to see all the different ways to pass a function as a callback. I copied that manual here and added some examples of each approach based on your scenario.
Callable
A PHP function is passed by its name as a string. Any built-in or user-defined function can be used, except language constructs such as: array(), echo, empty(), eval(), exit(), isset(), list(), print or unset().
// Not applicable in your scenario
$this->processSomething('some_global_php_function');
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.
// Only from inside the same class
$this->processSomething([$this, 'myCallback']);
$this->processSomething([$this, 'myStaticCallback']);
// From either inside or outside the same class
$myObject->processSomething([new MyClass(), 'myCallback']);
$myObject->processSomething([new MyClass(), 'myStaticCallback']);
Static class methods can also be passed without instantiating an object of that class by passing the class name instead of an object at index 0.
// Only from inside the same class
$this->processSomething([__CLASS__, 'myStaticCallback']);
// From either inside or outside the same class
$myObject->processSomething(['\Namespace\MyClass', 'myStaticCallback']);
$myObject->processSomething(['\Namespace\MyClass::myStaticCallback']); // PHP 5.2.3+
$myObject->processSomething([MyClass::class, 'myStaticCallback']); // PHP 5.5.0+
Apart from common user-defined function, anonymous functions can also be passed to a callback parameter.
// Not applicable in your scenario unless you modify the structure
$this->processSomething(function() {
// process something directly here...
});

As of PHP 8.1, we now have first-class callables. They use the syntax $callable = functionName(...). The three dots are part of the syntax and not an omission.
You can use the new syntax to create callable class methods.
Class MyClass {
public function myMethod() {
// first-class callables
$this->processSomething($this->myCallback(...));
$this->processSomething(self::myStaticCallback(...));
}
private function processSomething(callable $callback) {
// Process something...
$callback();
}
private function myCallback() {
// Do something...
}
private static function myStaticCallback() {
// Do something...
}
}
The three dots are not an omission/placeholder for parameters. They are a special syntax for creating a callable. If the method accepts no parameters, the syntax remains the same.

Since 5.3 there is a more elegant way you can write it, I'm still trying to find out if it can be reduced more
$this->processSomething(function() {
$this->myCallback();
});

You can also to use call_user_func() to specify a callback:
public function myMethod() {
call_user_func(array($this, 'myCallback'));
}
private function myCallback() {
// do something...
}

You can set the method return type to callable. It works for PHP 7.1
protected function myMethod(): callable
{
return function (int $j) {
};
}
Then call it like this:
someFunction($this->myMethod());

Related

How to reference a method within class as a callback to a custom function in PHP? [duplicate]

I have a class with methods that I want to use as callbacks.
How can I pass them as arguments?
Class MyClass {
public function myMethod() {
// How should these be called?
$this->processSomething(this->myCallback);
$this->processSomething(self::myStaticCallback);
}
private function processSomething(callable $callback) {
// Process something...
$callback();
}
private function myCallback() {
// Do something...
}
private static function myStaticCallback() {
// Do something...
}
}
Check the callable manual to see all the different ways to pass a function as a callback. I copied that manual here and added some examples of each approach based on your scenario.
Callable
A PHP function is passed by its name as a string. Any built-in or user-defined function can be used, except language constructs such as: array(), echo, empty(), eval(), exit(), isset(), list(), print or unset().
// Not applicable in your scenario
$this->processSomething('some_global_php_function');
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.
// Only from inside the same class
$this->processSomething([$this, 'myCallback']);
$this->processSomething([$this, 'myStaticCallback']);
// From either inside or outside the same class
$myObject->processSomething([new MyClass(), 'myCallback']);
$myObject->processSomething([new MyClass(), 'myStaticCallback']);
Static class methods can also be passed without instantiating an object of that class by passing the class name instead of an object at index 0.
// Only from inside the same class
$this->processSomething([__CLASS__, 'myStaticCallback']);
// From either inside or outside the same class
$myObject->processSomething(['\Namespace\MyClass', 'myStaticCallback']);
$myObject->processSomething(['\Namespace\MyClass::myStaticCallback']); // PHP 5.2.3+
$myObject->processSomething([MyClass::class, 'myStaticCallback']); // PHP 5.5.0+
Apart from common user-defined function, anonymous functions can also be passed to a callback parameter.
// Not applicable in your scenario unless you modify the structure
$this->processSomething(function() {
// process something directly here...
});
As of PHP 8.1, we now have first-class callables. They use the syntax $callable = functionName(...). The three dots are part of the syntax and not an omission.
You can use the new syntax to create callable class methods.
Class MyClass {
public function myMethod() {
// first-class callables
$this->processSomething($this->myCallback(...));
$this->processSomething(self::myStaticCallback(...));
}
private function processSomething(callable $callback) {
// Process something...
$callback();
}
private function myCallback() {
// Do something...
}
private static function myStaticCallback() {
// Do something...
}
}
The three dots are not an omission/placeholder for parameters. They are a special syntax for creating a callable. If the method accepts no parameters, the syntax remains the same.
Since 5.3 there is a more elegant way you can write it, I'm still trying to find out if it can be reduced more
$this->processSomething(function() {
$this->myCallback();
});
You can also to use call_user_func() to specify a callback:
public function myMethod() {
call_user_func(array($this, 'myCallback'));
}
private function myCallback() {
// do something...
}
You can set the method return type to callable. It works for PHP 7.1
protected function myMethod(): callable
{
return function (int $j) {
};
}
Then call it like this:
someFunction($this->myMethod());

Argument passed to function must be callable, array given

I'm trying to run a method on each element inside a collection. It's an object method residing in the same class:
protected function doSomething()
{
$discoveries = $this->findSomething();
$discoveries->each([$this, 'doSomethingElse']);
}
protected function doSomethingElse($element)
{
$element->bar();
// And some more
}
If I precede the call on Collection::each with the check is_callable([$this, 'doSomethingElse']) it returns true, so apparently it is callable. The call itself however throws an exception:
Type error: Argument 1 passed to Illuminate\Support\Collection::each() must
be callable, array given, called in ---.php on line 46
The method trying to be called can be found here.
I'm bypassing this by just passing a closure that itself simply calls that function, but this would definitely a much cleaner solution and I can't find out why it throws the error.
Change the visibility of your callback method to public.
protected function doSomething()
{
$discoveries = $this->findSomething();
$discoveries->each([$this, 'doSomethingElse']);
}
public function doSomethingElse($element)
{
$element->bar();
// And some more
}
Since PHP 7.1 you can leave your function protected. Now you can write:
protected function doSomething()
{
$discoveries = $this->findSomething();
$discoveries->each(\Closure::fromCallable([$this, 'doSomethingElse']));
}
protected function doSomethingElse($element)
{
$element->bar();
// And some more
}
Source
function with callback
public function foo(callable $callback){
$callback('something')
}
named function for callback
public function do($something) {
//
}
result
foo(function ($something) {
//
})
or call named function
foo(\Closure::fromCallable([$this, 'do']))
or
foo(this->do(...))
PHP >= 5.4
I wasn't able to reproduce your error, but my guess is that you should use $discoveries instead of $this in the callback array, like so:
$discoveries->each([$discoveries, 'doSomethingElse']);
Even though $discoveries and $this are of the same class, and therefore can access each other's protected and private methods, the type-hinting functionality may not check that the object in the callback array is the same class as the current class. However, the is_callable() method will check for this, which may explain why it returns true when you call it from inside the each() method.
PHP < 5.4
There is no type named callable, so when you use it as a type hint, it is referring to a class named callable. See this answer.

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
?>

can we alias(save to a variable) a class method in php

here is an example class:
public class example
{
private $foof;
public function __construct()
{
$this->foof = $this->foo;
}
public function foo($val=0)
{
// do something...
}
}
So basically, in the constructer of the sample code, is it possible to assign a class method to a variable?
Ultimately what i want is to have an associative array with all the class methods aliased in it...that possible in php?
In PHP5.3+ (which you should be using anyway!) you can simply create an anonymous function which calls your method:
$this->foof = function() {
$this->foo(1);
};
However, you cannot call it using $this->foof() - you have to assign it to a variable first: $foof = $this->foof; $foof();
In older PHP versions you cannot easily do this - create_function() does not create a closure so $this is not available there.
You don't need to use anonymous functions. Just use the Callable pseudo type.
$this->foof = array($this, 'foo');
...
call_user_func($this->foof);

Execute a method when an instance variable is referenced in a PHP class?

Is it possible to run a function when referring to a variable in a php class rather than simply returning its value, similar to javascript's ability for a variable to hold a method?
class LazyClassTest()
{
protected $_lazyInitializedVar;
public function __construct()
{
/* // How can this call and return runWhenReferrenced() when
// someone refers to it outside of the class:
$class = new LazyClass();
$class->lazy;
// Such that $class->lazy calls $this->runWhenReferrenced each
// time it is referred to via $class->lazy?
*/
$this->lazy = $this->runWhenReferrenced();
}
protected function runWhenReferrenced()
{
if (!$this->_lazyInitializedVar) {
$this->_lazyInitializedVar = 'someValue';
}
return $this->_lazyInitializedVar
}
}
PHP5s magic method __get($key) and __set($key, $value) might be what you need. More information about them is available in the PHP manual.
This sounds like PHP5.3: lambda / closures / anonymous functions
http://php.net/manual/en/functions.anonymous.php:
<?php
$greet = function($name) {
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
You are probably heading in the wrong direction. You normally want to define a getter getLazyVar(). There is a reason why people always make properties protected and defined getters / setters: So they can pre- or postprocess the values.

Categories