В PHP для определения обратного вызова можно использовать замыкание, а инструментом для передачи статических параметров является use
директивы.
class MyClass {
public function foo($x) {
echo $x;
}
public function bar() {
$x = '123';
$callback = function () use ($x) {
$this->foo($x);
};
$callback();
}
}
$myClass = new MyClass();
$myClass->bar();
Возможно ли / Как избежать анонимной функции и заменить ее методом?
class MyClass {
public function foo($x) {
echo $x;
}
public function baz() {
$x = '567';
// There is no function with the name create_user_func.
// Just to show, what I'm looking for.
$callback = create_callback([$this, 'foo'], $params = [$x]);
$callback();
}
}
$myClass = new MyClass();
$myClass->baz();
РЕДАКТИРОВАТЬ:
Некоторая дополнительная информация / справочная информация (чтобы прояснить, чего я хочу достичь и почему — и чтобы избежать недоразумений):
В моем конкретном случае мне нужно передать обратный вызов в метод фреймворка. Это означает: я не могу / не могу влиять на то, как он вызывается.
Метод принимает только сам обратный вызов, без аргументов для обратного вызова. Это означает, что обратный вызов должен «знать» / предоставлять статические параметры (и их значения), в которых он нуждается.
Это именно то, что use
Директива решает. Но у меня есть несколько определений обратного вызова в моем методе, и метод становится длинным. Поэтому я хочу перенести логику обратных вызовов в отдельные методы.
Но у меня есть несколько определений обратного вызова в моем методе, и метод становится длинным. Поэтому я хочу перенести логику обратных вызовов в отдельные методы.
Это идеальный пример для магического метода __invoke()
Для каждого необходимого обратного вызова извлеките функциональность и свойства, которые он использует, в новый класс. Поместите код в __invoke()
метод нового класса, инициализировать все свойства, в которых он нуждается __construct()
и ты готов к работе.
Код:
class MyClass {
public function bar() {
$x = '123';
// Create the callback, pass the values it needs to initialize
$callback = new ActionFoo($x);
// Call the callback without arguments
$callback();
}
}
class ActionFoo {
private $x;
public function __construct($x) {
$this->x = $x;
}
public function __invoke() {
echo($this->x);
}
}
$myClass = new MyClass();
$myClass->bar();
Я думаю, будет справедливо сказать, что вы пытаетесь подражать Javascript bind
метод. Проблема с этим в PHP заключается в том, что функции не являются гражданами или объектами первого класса, поэтому что-то вроде ->bind($x)
это невозможно. Там также нет способа передать дополнительные параметры для callable
. Итак, вы собираетесь иметь обернуть что-то.
Более пригодный для повторного использования метод — написать соответствующий класс:
class CallbackWrapper {
protected $callable,
$args;
public function __construct(callable $callable, array $args) {
$this->callable = $callable;
$this->args = $args;
}
public function __invoke() {
call_user_func_array($this->callable, $this->args);
}
}
giveMeACallback(new CallbackWrapper([$this, 'foo'], [$x]));
Или вы просто упростите создание анонимных функций:
function make_callback(callable $callable, array $args) {
return function () use ($callable, $args) {
return call_user_func_array($callable, $args);
};
}
giveMeACallback(make_callback([$this, 'foo'], [$x]));
Есть много способов достичь этого.
Код:
class MyClass {
private $x;
public function foo() {
echo $this->x;
}
public function bar() {
$this->x = '123';
anon($this);
}
}
$myClass = new MyClass();
$myClass->bar();
function anon($obj) {
$obj->foo();
}
call_user_func
,Код:
class MyClass {
private $x;
public function foo() {
echo $this->x;
}
public function bar() {
$this->x = '123';
call_user_func([$this, 'foo']);
}
}
$myClass = new MyClass();
$myClass->bar();
call_user_func_array
,Код:
class MyClass {
private $x;
public function foo($x) {
echo $x;
}
public function bar() {
$x = '123';
call_user_func_array([$this, 'foo'], [$x]);
}
}
$myClass = new MyClass();
$myClass->bar();