【问题标题】:php - Access outer class from an anonymous callbackphp - 从匿名回调访问外部类
【发布时间】:2015-03-31 16:08:23
【问题描述】:

我有这样的代码:

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 应用程序。我想优雅地停止服务器。

谁能告诉我如何访问回调中的stopperstopServer?我可以使用以下语法吗?

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

我也想过在回调中存储类值,但是setStopper是动态调用的,值可能不会更新!

有没有更好的方法来处理这种情况?

跟进: php - Dynamically update Singleton class' value

【问题讨论】:

    标签: php class callback anonymous-function


    【解决方案1】:

    您可以在$consumer 对象和词法对象$this 周围创建一个Closure(如果您使用的是PHP $this 重命名为其他名称,因为您不能@ 987654326@):

     $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 的额外引用将一直存在,直到类实例本身被销毁。

    没有意识到这一点可能会导致一些严重的性能问题。

    【讨论】:

    • setStopper 中更新stopper 是否会影响回调中的$stopper? php中的所有内容都是“通过引用”吗?
    • 对象是,是的。见here
    • 好吧!我将更新我的代码并验证它是否正在运行,谢谢,并会通知您
    • 嘿,介意我再问一个问题吗?如果我将其用作单例类,并执行另一个获取实例并设置停止器的 php 脚本,它实际上并没有停止消耗!我能知道为什么吗?
    • 我的意思是如果整个事情都是通过引用工作的,如果我理解单例类的工作,设置停止器应该停止服务器对吗?但事实并非如此!即使在我调用setStopper 之后,塞子仍然是false
    【解决方案2】:

    同样的问题在这里我使用来自 ob_start/ob_end_flush 的输出缓冲区 我拥有的一个函数应该是动态的(但是我推入的参数应该将它们插入一个数组中,以供以后使用 $buffer 解析缓冲区) 在与 ob_start 关联的解析器中,我从一个充满数据的数组中获得了这些代码行:

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

    我只使用一个类单例,并且我经常使用“::”。 你怎么看我的情况 array_filter 在没有 &$buffer 的情况下出现故障

    【讨论】: