我正在尝试编写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)不实现可序列化的接口,也不实现必需的sleepwakeup方法。因此,我们不应该序列化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;
    }
}

10-08 03:22