2

PHP DOM実装を使用して、DOMElementsのサブクラスを含むカスタムドキュメントツリーを作成できましたが、非常に奇妙なことがわかりました。DOMDocumentを複製または返すと、子ノードクラスが変更されるようです。

基本例

class Section extends DOMElement
{
  public function __construct($name, $value = null, $uri = null)
  {
    parent::__construct($name, $value, $uri);
  }
}

class Paragraph extends DOMElement
{
  public function __construct($name, $value = null, $uri = null)
  {
    parent::__construct($name, $value, $uri);
  }
}

function display_doc($label, DOMDocument $doc)
{
  $endl = (PHP_SAPI == "cli") ? "\n" : "<br />";
  $pad  = (PHP_SAPI == "cli") ? "\t" : "  ";
  echo ($label . $endl);

  $root = $doc->documentElement;
  echo ($pad . "root " . get_class($root) . $endl);
  echo ($pad . "first child " . get_class($root->firstChild) . $endl);
}

function test_dom($name, DOMDocument &$instance = null)
{
  $doc = ($instance) ? $instance : new DOMDocument("1.0", "utf-8");
  $root = $doc->appendChild($doc->createElement("root"));
  $section = new Section("section");

  $root->appendChild($section);
  $paragraph = new Paragraph("para");
  $section->appendChild($paragraph);

  $clone = clone $doc;

  display_doc($name . " - Inside function", $doc);
  display_doc($name . " - Inside function (clone)", $clone);

  return $doc;
}

$doc = test_dom("Using new instance");
display_doc("Returned doc in global scope", $doc);

$doc2 = new DOMDocument("1.0", "utf-8");
test_dom("Using global scope instance", $doc2);
display_doc("Modified doc in global scope", $doc2);

出力します

新しいインスタンスの使用-内部関数
    ルートDOMElement
    最初の子セクション
新しいインスタンスの使用-内部関数(クローン)
    ルートDOMElement
    最初の子DOMElement
グローバルスコープで返されたドキュメント
    ルートDOMElement
    最初の子DOMElement
グローバルスコープインスタンスの使用-内部関数
    ルートDOMElement
    最初の子セクション
グローバルスコープインスタンスの使用-内部関数(クローン)
    ルートDOMElement
    最初の子DOMElement
グローバルスコープで変更されたドキュメント
    ルートDOMElement
    最初の子DOMElement

ドキュメントが複製または返されると、最初の子のクラスが単純からSection単純に変わります(参照によっても)DOMElement

  • 私のPHPバージョンは5.3.10ですが、同じ動作が5.4でも発生します
  • DOMDocument :: registerNodeClassを使用するとDOMElement、登録されたノードクラスによって変換されますが、次のサブクラスが複数あります。DOMElement

私の質問は、実際には回避策や別の解決策を見つけることではありませんが、ここで何が起こっているのか、そしてどのメカニズムによって子ノードが変換されるのかを理解したいと思います。

編集:この問題に関連するバグレポート(2歳)を見つけました:http://www.mail-archive.com/php-bugs@lists.php.net/msg134710.html。提案された回避策はうまく機能しますが、それが実際のバグなのか、DOMAPIの無効な使用なのかは不明です。

4

1 に答える 1

1

を使用する場合new Paragraphnew Sectionそれらをメモリに保持するために別の配列に格納する必要があるため、DOMDocumentデフォルトのクラスを使用するだけではありません。

DOMバグレポートは正確であり、PHPでの実装全体に欠陥があると私は考えています。

オブジェクトのコピーを他の場所に保持することは、とにかくDOMを使用する場合と同様に、メモリを大量に消費します。私は多くの欠陥のためにまともな実装を機能させるために個人的に苦労しています、それであなただけではありません:)

于 2014-02-22T12:08:49.987 に答える