Доступ к внешнему классу из анонимного обратного вызова

У меня есть такой код:

class Server {
private $stopper;

public function setStopper() { $this->stopper = TRUE; }

public function startServer() {
$consumer = new Consumer();
$consumer->onConsume(function($data) {
global $consumer;
// some processing
if( ?? ) { // how to access stopper here??
$consumer->stop();
// also how to access stopServer() here??
}
});
$consumer->consume();
}

public function stopServer() { ... }

}

Этот код находится в файле, который должен работать вечно, если только setStopper() называется. Пока у меня есть set_time_limit чтобы остановить код через некоторое время. Но мне нужно реализовать setStopper Таким образом, я могу остановить сервер, когда это необходимо, а не «через некоторое время».

Мне это нужно, потому что onConsume подключен к потоковому API и выполняет анонимный обратный вызов всякий раз, когда новые данные становятся доступными, и я не хочу, чтобы приложение php по тайм-ауту завершалось из-за некоторых проблем с блокировкой. Я хочу изящно остановить сервер.

Может кто-нибудь, пожалуйста, расскажите, как получить доступ к stopper или же stopServer внутри обратного вызова? Могу ли я использовать следующий синтаксис?

...(function($data) use ($this) {...

Я также думал о сохранении значения класса внутри обратного вызова, но setStopper вызывается динамически, и значение может не обновляться!

Есть ли лучший способ справиться с этой ситуацией?

Следовать за: php — динамически обновлять значение класса Singleton

1

Решение

Вы можете создать закрытие вокруг $consumer объект, а также лексический объект $this (если вы используете PHP < 5.4, ​​вам нужно переименовать $this к чему-то другому, потому что вы не можете use($this)):

 $self = $this;
// You may not need to do this, I cannot remember off-hand whether
// closures have access to private variables or not
$stopper = $this->stopper;
$consumer->onConsume(function($data) use($consumer, $self, $stopper) {
if( $stopper ) {
$consumer->stop();
$self->stopServer();
}
});

См. Пример № 3 на странице справки.

Для полноты картины я также должен отметить, что если это долгоживущий процесс, то объекты, на которые ссылаются внутри замыкания, будут зависать еще долго после выхода из функции. Например:

function makeAdder($x) {
return function($n) use($x) {
return $x + $n;
};
}

$adder = makeAdder(5);
echo $adder(2); // Output 7
echo $adder(5); // Output 10
echo $adder(4); // Output 9

Это классический пример закрытия. Обычно, как только makeAdder функция возвращает свою внутреннюю переменную $x выйдет за рамки и будет готов к сбору мусора. Однако, поскольку он ограничен областью действия анонимной функции, он будет зависать бесконечно (до завершения скрипта) или же ссылка на содержащую область также освобождается (т.е. через unset($adder)). Это означает, что после вызова вашей функции дополнительные ссылки на $consumer, $this а также $stopper будет зависать, пока сам экземпляр класса не будет уничтожен.

Незнание этого может привести к серьезным проблемам с производительностью.

1

Другие решения

та же проблема здесь я использую выходные буферы из ob_start / ob_end_flush
и одна функция, которая у меня есть, должна быть динамической (однако параметры, в которые я нажимаю, должны вставить их в массив для последующего использования для разбора буферов, используя $ буфер)
в парсере, связанном с ob_start за раз, у меня есть эти строки кода из одного массива данных:

if(!empty($this->__b2))
array_filter ($this->__b2,function($var)use(**&$buffer**){
$buffer = preg_replace("/<\/body>/i", $var.'</body>', $buffer);
});

Я использую только один класс singleton, и я часто использую «::».
Как вы видите в моем случае
Массив_фильтр вышел из строя без &$ буфер

0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector