我正在尝试编写php线程。我正在构造器中创建一个domdocument,但是由于某种原因,新创建的文档虽然被分配给了一个成员变量,但却消失了。
代码清单1:
class workerThread extends Thread {
private $document;
private $i;
public function __construct($i){
$this->document = new DOMDocument();
$this->i = $i;
}
public function run(){
try{
$root = $this->document->createElement("Root");//can't fetch this
$this->document->appendChild($root);
}catch(RuntimeException $e){
return false;
}
}
public function getRoot(){
return $this->document->documentElement;
}
}
for($i=0;$i<10;$i++){
$workers[$i] = new workerThread($i);
$workers[$i]->start();
}
for($i=0;$i<10;$i++){
$workers[$i]->join();
}
?>
我尝试在构造函数外实例化新的domdocument,并将它们用作构造函数中的参数,如代码清单2所示,但它没有改变任何东西。
代码清单2:
for($i=0;$i<10;$i++){
$documents[$i] = new DOMDocument();
$workers[$i] = new workerThread($documents[$i], $i);
$workers[$i]->start();
}
构造函数如下所示:
代码清单3:
public function __construct($doc, $i){
$this->document = $doc;
$this->i = $i;
}
我希望能够在线程外部或内部创建domdocument(无论它是在构造函数、run函数还是其他函数中),在run函数中使用它,并从处理它的线程外部检索它的根。
最佳答案
问题是DOMDocument
类不能可靠地序列化。根据serialize
功能手册:
注意,许多内置的php对象不能序列化。但是,具有这种能力的人要么实现可序列化接口,要么实现magic uuu sleep()和uuu wakeup()方法。如果一个内部类不满足这些要求中的任何一个,它就不能可靠地序列化。
正如我们所看到的,DOMDocument
类(和扩展名,它的父类,DOMNode
)不实现可序列化的接口,也不实现必需的sleep
和wakeup
方法。因此,我们不应该序列化DOMDocument
类。
那么,序列化和这个问题有什么关系呢?好吧,pthreads在内部序列化所有非Threaded
类(除了Closure
)和Threaded
对象属性的数组。这意味着在将新的DOMDocument
对象分配给workerThread::$document
属性时,pthreads会在内部序列化该属性并将其存储为字符串。当您获取这个属性时,pthreads会将其取消序列化,以供您正常使用。(这只是pthreads为了在多线程环境中安全工作而必须使用的众多hacks之一。)
因此,在构造函数内部、类外部或workerThread::run
方法内部分配这个属性并不重要,您仍然会遇到同样的问题。
那么,解决办法是什么?好吧,你可以做几件事。您可以只将生成的xml保存到workerThread::$document
属性中,也可以使用可序列化的友好类扩展domdocument类,并将其用于workerThread::$document
属性。最终,这两种解决方案都需要将domdocument对象转换为xml,因为这是将其存储为Threaded
属性(直接或间接)的唯一安全方法。
应用第一个(更简单的)解决方案,下面是您的workerThread
类的工作版本:
class workerThread extends Thread
{
private $document;
private $i;
public function __construct($i)
{
$this->i = $i;
}
public function run()
{
$document = new DOMDocument();
try {
$root = $document->createElement("Root");
$document->appendChild($root);
} catch (RuntimeException $e) {
return false;
}
$this->document = $document->saveXML();
}
public function getRoot()
{
$document = new DOMDocument();
$document->loadXML($this->document);
return $document->documentElement;
}
}