1

この例を参照してください。

このクラスはDOMElementを拡張します。すべてのDOMElementは、変更可能であるためにDOMDocuementの一部である必要があります。

class Xmlrize  extends DOMElement
{
    private static $dom;

    public function __construct(/*. string .*/ $name,$value =null) {
        parent::__construct($name,$value,null);
    if(!self::$dom) {
            self::$dom = new DOMDocument('1.0','UTF-8');
        }
        self::$dom->appendChild($this);
    }
}

配列をDOMに追加するために使用されます。配列の値がXmlrizeでない場合は、無視します。

class Attributes extends Xmlrize {

    public function __construct(array $attributes)
    {
        parent::__construct('Attributes');

        foreach($attributes as $name => $value) {
            $element = new Xmlrize($name);
            if($value instanceof Xmlrize)
                $element->appendChild($value);
            $this->appendChild($element);
        }
    }
}

コンストラクターに属性のインスタンスを追加できます

class Html extends Xmlrize {

    public function __construct(Attributes $obj) {
        parent::__construct('html');
        $this->addAttributes($obj);
    }

このメソッドは、属性がXmlrizeのインスタンスであるかどうかを示します。

    protected function addAttributes(Attributes $attributes)
    {
        foreach($attributes->childNodes as $attribut) {
           if($attribut->childNodes->length == 1) {
                $item = $attribut->childNodes->item(0);
            echo $attribut->nodeName.': ';
            echo $item->nodeName.' has value '.$item->nodeValue.'. ';
            echo 'Is it DomElement? ';
            echo ($item instanceof DomElement) ? 'true' : 'false';
            echo '. Is it Xmlrize? ';
            echo ($item instanceof Xmlrize) ? 'true' : 'false';
            echo '.'.PHP_EOL;
           }
        }
        return null;
    }
}

配列による属性の開始の例。違いを見てください!

/* works as expected */
$like = new Html(new Attributes(
            $xx =  array('XXX'=> new Xmlrize('foo', 'baar'))
));

/* do not work as exptected */
$like = new Html(new Attributes(
              array('XXX'=> new Xmlrize('foo', 'baar'))
));
?>

上記の例は次を返します。

XXX: foo has value baar. Is it DomElement? true. Is it Xmlrize? true.
XXX: foo has value baar. Is it DomElement? true. Is it Xmlrize? false.

'$ xx ='を追加すると、要素はXmlrizeと見なされ、そうでない場合はそうではないのはなぜですか?

4

2 に答える 2

1

おめでとうございます。PHPのDOMの実装にバグが見つかりました。私はあなたのコードにしばらく時間を費やし、バグのある動作をこの単純なテストケースに絞り込むことができました。

class MyElement extends DOMElement { }

// #1 - okay
$dom = new DOMDocument();
$e = new MyElement("e");
$dom->appendChild($e);
echo get_class($dom->childNodes->item(0)) . "\n";

// #2 - wrong
$dom = new DOMDocument();
$dom->appendChild(new MyElement("e"));
echo get_class($dom->childNodes->item(0)) . "\n";

// #3 - wrong
$dom = new DOMDocument();
$e = new MyElement("e");
$dom->appendChild($e);
$e = null;
echo get_class($dom->childNodes->item(0)) . "\n";

これは明らかにPHPのバグですが、これが発生する理由はここにあります。PHPのすべてのオブジェクトには、参照カウントがあります(このオブジェクトへの参照がどこかにいくつありますか)。を呼び出すと$dom->appendChild(...)、この関数はオブジェクトの参照数を内部的に増やす必要がありますが、そうではありません。サンプル#1を実行すると、すべて問題ないように見えますが、サンプル#2では、オブジェクトはrefcount 1で「一時的に」作成されます(呼び出しのみ)。完了するappendChildと、PHPはrefcountを0に減らし、したがって、メモリからのオブジェクト。

ここで注意が必要な部分があります。「すごい、つまり、割り当て解除された(デッド)メモリへのポインタがあり、プログラムがひどくクラッシュするはずだ」と考える必要があります。ただし、PHPのメモリマネージャが未使用のメモリを実際に割り当て解除しないという理由だけでなく、割り当て解除としてマークするだけです。したがって、メモリの内容は別の割り当てによってすでに変更されている可能性がありますが、たとえば、そこから読み取ることができます。そして、それが実際に起こることです。オブジェクトが実際に割り当て解除されていることをデバッガーで確認しました(明らかにそうではないはずです。DOM階層からの参照が必要です)。

ここで行うべきことは、1)バグレポートをPHPのWebサイトに送信し、2)DOMElementクラスの使用を停止するか、DOMの階層に「追加」するすべてのオブジェクトが別の場所を参照していることを確認することです。

また、まだ明確でない場合は、との間で異なる動作が発生した理由がここにありますfoo(array(...))。2foo($x = array(...))つ目は、配列をグローバル(またはローカル、呼び出し先によって異なります)変数に割り当て、配列と配列内を保持します。オブジェクトへの参照があります。したがって、割り当てが解除されることはなく、DOMの階層は問題ありません。

バグレポートを提出するかどうか教えてください。必要に応じて代わりに行いますが、それはあなたのバグです:)

于 2012-04-20T15:32:03.583 に答える
0

foo(array(…))との唯一の違いfoo($x=array(…))は次のとおりです。

foo(array(…))配列を引数としてfooメソッドに渡すだけです。

foo($x=array(…))配列を$x変数に保存し、同じ変数$xをfooメソッドに渡します。

于 2012-04-20T13:35:43.603 に答える