php - 从匿名回调访问外部 class
php - Access outer class from an anonymous callback
我有这样的代码:
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
方式,这样我就可以在需要时停止服务器,而不是 "after a while".
我需要这个,因为 onConsume
连接到流 API 并且 运行 每当有新数据可用时匿名回调,我不想杀死php 应用程序由于某些锁定问题而超时。我想优雅地停止服务器。
谁能告诉我如何访问回调中的 stopper
或 stopServer
?我可以使用以下语法吗?
...(function($data) use ($this) {...
我也想过在回调中存储class值,但是setStopper
是动态调用的,值可能不会更新!
有没有更好的方法来处理这种情况?
跟进:
您可以围绕 $consumer
对象和词法对象 $this
创建一个 Closure(如果您使用的是 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
这是闭包的 classic 示例。通常,一旦 makeAdder
函数 returns 其内部变量 $x
将超出范围并准备好进行垃圾收集。然而,由于它被绑定在匿名函数的范围内,它将无限期地挂起(直到脚本终止)或对包含范围的引用也被释放(即通过unset($adder)
).这意味着一旦您的函数被调用,对 $consumer
、$this
和 $stopper
的额外引用将一直存在,直到 class 实例本身被销毁。
没有意识到这一点会导致一些严重的性能问题。
同样的问题,我使用来自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);
});
我只使用一个 class 单例,而且我经常使用“::”。
你怎么看我的情况
array_filter 在没有 &$buffer
的情况下是乱序的
我有这样的代码:
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
方式,这样我就可以在需要时停止服务器,而不是 "after a while".
我需要这个,因为 onConsume
连接到流 API 并且 运行 每当有新数据可用时匿名回调,我不想杀死php 应用程序由于某些锁定问题而超时。我想优雅地停止服务器。
谁能告诉我如何访问回调中的 stopper
或 stopServer
?我可以使用以下语法吗?
...(function($data) use ($this) {...
我也想过在回调中存储class值,但是setStopper
是动态调用的,值可能不会更新!
有没有更好的方法来处理这种情况?
跟进:
您可以围绕 $consumer
对象和词法对象 $this
创建一个 Closure(如果您使用的是 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
这是闭包的 classic 示例。通常,一旦 makeAdder
函数 returns 其内部变量 $x
将超出范围并准备好进行垃圾收集。然而,由于它被绑定在匿名函数的范围内,它将无限期地挂起(直到脚本终止)或对包含范围的引用也被释放(即通过unset($adder)
).这意味着一旦您的函数被调用,对 $consumer
、$this
和 $stopper
的额外引用将一直存在,直到 class 实例本身被销毁。
没有意识到这一点会导致一些严重的性能问题。
同样的问题,我使用来自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);
});
我只使用一个 class 单例,而且我经常使用“::”。 你怎么看我的情况 array_filter 在没有 &$buffer
的情况下是乱序的