У меня такой код:
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 при тайм-ауте из-за некоторых проблем с блокировкой. Я хочу изящно остановить сервер.
Может ли кто-нибудь рассказать, как получить доступ к stopServer
или stopServer
внутри обратного вызова? Могу ли я использовать следующий синтаксис?
...(function($data) use ($this) {...
Я также думал о сохранении значения класса внутри обратного вызова, но setStopper
называется динамически, и значение может не обновляться!
Есть ли лучший способ справиться с этой ситуацией?
Follow Up: php – динамическое обновление значения Singleton class
Вы можете создать Closure вокруг объекта $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
функция makeAdder
возвращает свою внутреннюю переменную $x
она выпадет из области видимости и будет готова к сбору мусора. Поскольку он, однако, связан с областью анонимной функции, он будет бесконечно зависать (до завершения сценария) или ссылки на содержащую область видимости (т.е. через unset($adder)
). Это означает, что после вызова вашей функции дополнительные ссылки на $consumer
, $this
и $stopper
будут зависать, пока сам экземпляр класса не будет уничтожен.
Не осознавая этого, это может привести к серьезным проблемам с производительностью.
та же проблема здесь я использую выходные буферы из ob_start / ob_end_flush, и одна функция i должна быть динамической (однако параметры, которые я вставляю, должны вставлять их в массив для последующего использования для разбора буферов с использованием $ buffer ) в парсере, связанном с ob_start при я имею эти строки кода из одного массива, полного данных:
if(!empty($this->__b2)) array_filter ($this->__b2,function($var)use(**&$buffer**){ $buffer = preg_replace("/<\/body>/i", $var.'</body>', $buffer); });
Я использую только один класс singleton, и я использую «::» много. Как вы видите, в моем случае array_filter вышел из строя без буфера & $