I am trying to store a callable/closure as a class field/property.
My initial attempt was this:
class MyClass
{
protected callable $modifier;
public function __construct(callable $modifier) {
$this->modifier = $modifier;
}
}
class SomeOtherClass
{
public static function func()
{
return ['a' => 'b'];
}
}
$test = new MyClass('SomeOtherClass::func');
This returned an error of:
$modifier cannot have type callable
Then, after reading this online, I've tried this with no success:
class MyClass
{
protected Closure $modifier;
public function __construct(callable $modifier) {
$this->modifier = Closure::fromCallable($modifier);
}
}
class SomeOtherClass
{
public static function func()
{
return ['a' => 'b'];
}
}
$test = new MyClass('SomeOtherClass::func');
This last one returns this error:
Argument #1 ($modifier) must be of type callable, string given
Then I've tried this:
class MyClass
{
protected Closure $modifier;
public function __construct(callable $modifier) {
$this->modifier = Closure::fromCallable($modifier);
}
}
class SomeOtherClass
{
public static function func()
{
return ['a' => 'b'];
}
}
$test = new MyClass(['SomeOtherClass', 'func']); // <----- changed string to an array
Which returns this error:
Argument #1 ($modifier) must be of type callable, array given
Is this even possible to do in PHP?
Assuming you're using PHP 8.1 or above (which at the time of writing are the only supported versions of PHP anyway), then you can use first-class callable syntax, as introduced in 8.1.
To do this, you use the name of a function and then (...)
as the argument to pass in.
In your case, you could therefore do this:
class MyClass
{
protected Closure $modifier;
public function __construct(callable $modifier) {
$this->modifier = Closure::fromCallable($modifier);
}
public function runClosure()
{
var_dump(($this->modifier)());
}
}
class SomeOtherClass
{
public static function func()
{
return ['a' => 'b'];
}
}
$test = new MyClass(SomeOtherClass::func(...));
$test->runClosure();
Live demo: https://3v4l.org/nMmvq
N.B. The code above assumes that you want to use func()
as a static method (as defined in your sample code). If anyone is reading and wants to do something similar but with an instance method, you'd need a small adjustment as follows:
class MyClass
{
protected Closure $modifier;
public function __construct(callable $modifier) {
$this->modifier = Closure::fromCallable($modifier);
}
public function runClosure()
{
var_dump(($this->modifier)());
}
}
class SomeOtherClass
{
public function func()
{
return ['a' => 'b'];
}
}
$soc = new SomeOtherClass();
$test = new MyClass($soc->func(...));
$test->runClosure();
Live demo: https://3v4l.org/iEAiM