简体   繁体   中英

php - Access outer class from an anonymous callback

I have a code like this:

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() { ... }

}

This code is in a file that should run forever unless the setStopper() is called. So far I have set_time_limit to stop the code after a while. But I need to implement setStopper way so I can stop the server whenever needed, not "after a while".

I need this because, the onConsume is connected to a streaming API and runs the anonymous call back whenever new data is available and I don't want kill the php app on timeout due to some lock issues. I want to gracefully stop the server.

Can anyone please tell how to access the stopper or stopServer inside the callback? Can I use following syntax?

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

I also thought of storing the class value inside callback, but the setStopper is called dynamically and the value might not be updated!

Is there a better way to handle this situation?

Follow Up: php - Dynamically update Singleton class' value

You can create a Closure around the $consumer object as well as the lexical object $this (if you're using PHP < 5.4, you need to rename $this to something else, because you cannot 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();
  }
});

See Example #3 on the linked to manual page.

I should also note here for completeness that if this is a long-lived process, then the objects being referenced inside the closure will hang around long after the function exits. For instance:

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

This is a classic example of a closure. Normally, once the makeAdder function returns its inner variable $x will fall out of scope and be ready for garbage collection. Since it is however bound inside the anonymous function's scope, it will hang around indefinitely (until the script's termination) or the reference to the containing scope is also released (ie via unset($adder) ). This means that once your function is called, extra references to $consumer , $this and $stopper will hang around until the class instance itself is destroyed.

Not being aware of this can lead to some serious performance issues.

the same problem here i use output buffers from ob_start/ob_end_flush and one function i have should be dynamic (however parameters i push into should insert them in an array for later use for parsing buffers using $buffer ) in the parser associated to ob_start at a time i have these lines of code from one array full of data :

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

I use a only one class singleton ,and i use "::" a lot. How you see in my case array_filter was out of order without &$buffer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM