Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】Dom\EntityReference::DOCUMENT_POSITION_CONTAINED_BY定数の使い方

DOCUMENT_POSITION_CONTAINED_BY定数の使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

『DOCUMENT_POSITION_CONTAINED_BY定数は、DOMドキュメント内における2つのノードの位置関係を示すために使用される、あらかじめ定義された値の一つです。具体的には、基準となるノードが、比較対象のノードに内包されている状態を表します。この定数は主に Dom\Node::compareDocumentPosition() メソッドの戻り値に含まれるビットフラグとして利用されます。このメソッドは、2つのノードの相対的な位置を評価し、その結果をビットマスクとして返却します。返された値に DOCUMENT_POSITION_CONTAINED_BY のビットが含まれている場合、それはメソッドを呼び出したノードが引数で渡されたノードの子孫、つまり内側にあることを意味します。開発者は、この定数とビット単位の論理積(&)演算子を用いて、戻り値から特定の関係性を判定することができます。これにより、プログラム上でDOMツリーの構造を正確に把握し、ノード間の包含関係に基づいた処理を実装することが可能になります。

構文(syntax)

1<?php
2
3$xml = <<<XML
4<?xml version="1.0"?>
5<!DOCTYPE root [<!ENTITY sample "text">]>
6<root><parent>&sample;</parent></root>
7XML;
8
9$doc = new Dom\Document();
10$doc->loadXML($xml);
11
12$parent = $doc->getElementsByTagName('parent')[0];
13$entityRef = $parent->firstChild;
14
15$position = $entityRef->compareDocumentPosition($parent);
16
17if ($position & Dom\EntityReference::DOCUMENT_POSITION_CONTAINED_BY) {
18    echo "The node is contained by the other node.";
19}
20
21?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

int

DOCUMENT_POSITION_CONTAINED_BYは、あるDOMノードが別のDOMノードに完全に含まれていることを示す整数値です。

サンプルコード

PHP DOMノード位置比較 DOCUMENT_POSITION_PRECEDING を調べる

1<?php
2
3/**
4 * Dom\Node::compareDocumentPosition メソッドを使用して、
5 * 2つのノード間の位置関係を比較する例を示します。
6 *
7 * この関数では、Dom\Node::DOCUMENT_POSITION_CONTAINED_BY や
8 * Dom\Node::DOCUMENT_POSITION_PRECEDING など、
9 * compareDocumentPosition メソッドが返すビットマスクを解析します。
10 *
11 * 元のリファレンス情報は Dom\EntityReference クラスに定数を指定していますが、
12 * 実際にはこれらの定数と compareDocumentPosition メソッドは
13 * Dom\Node クラス(または DOMNode)に定義されています。
14 * Dom\EntityReference は Dom\Node を継承しているため、
15 * Dom\Node クラスの定数とメソッドを使用することで、
16 * キーワードに関連する機能を示します。
17 */
18function demonstrateDomNodePositionComparison(): void
19{
20    // HTML文書をロードするためのDOMDocumentオブジェクトを作成
21    $dom = new DOMDocument();
22    // 簡潔なHTML構造をロードして比較対象のノードを用意
23    $dom->loadHTML('
24        <!DOCTYPE html>
25        <html>
26        <body>
27            <div id="container">
28                <span id="elementA">Hello</span>
29                <p id="elementB">World</p>
30            </div>
31            <div id="siblingC">Another section</div>
32        </body>
33        </html>
34    ');
35
36    // 比較に使用するノードを取得
37    // PHP 8では Dom\Element クラスが返されますが、Dom\Node を継承しているため比較メソッドは利用可能です
38    $container = $dom->getElementById('container');
39    $elementA = $dom->getElementById('elementA');
40    $elementB = $dom->getElementById('elementB');
41    $siblingC = $dom->getElementById('siblingC');
42
43    // 必要なノードが取得できなかった場合はエラーを表示して終了
44    if (!$container || !$elementA || !$elementB || !$siblingC) {
45        echo "エラー: 比較に必要なDOM要素の一部が見つかりませんでした。\n";
46        return;
47    }
48
49    echo "--- Dom\\Node::compareDocumentPosition メソッドによるノード位置関係の比較例 ---\n\n";
50
51    // --------------------------------------------------------------------------------
52    // 例1: 親子関係の比較 - 子ノードから親ノードへ
53    echo "1. elementA と container の比較 (elementA は container の子孫)\n";
54    // elementA が container と比べてどこに位置するかを比較
55    $positionResult = $elementA->compareDocumentPosition($container);
56    echo "  結果のビットマスク (int): " . $positionResult . "\n";
57
58    // Dom\Node::DOCUMENT_POSITION_CONTAINED_BY 定数を使用して、
59    // 現在のノード(elementA)が比較対象ノード(container)に含まれているかをチェック
60    if ($positionResult & Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) {
61        echo "  - elementA は container に含まれています (CONTAINED_BY).\n";
62    }
63    echo "\n";
64
65    // --------------------------------------------------------------------------------
66    // 例2: 逆の親子関係の比較 - 親ノードから子ノードへ
67    echo "2. container と elementA の比較 (container は elementA の祖先)\n";
68    // container が elementA と比べてどこに位置するかを比較
69    $positionResult = $container->compareDocumentPosition($elementA);
70    echo "  結果のビットマスク (int): " . $positionResult . "\n";
71
72    // Dom\Node::DOCUMENT_POSITION_CONTAINS 定数を使用して、
73    // 現在のノード(container)が比較対象ノード(elementA)を含んでいるかをチェック
74    if ($positionResult & Dom\Node::DOCUMENT_POSITION_CONTAINS) {
75        echo "  - container は elementA を含んでいます (CONTAINS).\n";
76    }
77    echo "\n";
78
79    // --------------------------------------------------------------------------------
80    // 例3: 兄弟ノード間の比較 (キーワード: document_position_preceding に関連)
81    echo "3. elementA と elementB の比較 (elementA は elementB より前に現れる兄弟)\n";
82    // elementA が elementB と比べてどこに位置するかを比較
83    $positionResult = $elementA->compareDocumentPosition($elementB);
84    echo "  結果のビットマスク (int): " . $positionResult . "\n";
85
86    // Dom\Node::DOCUMENT_POSITION_PRECEDING 定数を使用して、
87    // 比較対象ノード(elementB)が現在のノード(elementA)より文書上で前に現れるかをチェック
88    // しかし、このケースでは elementA が elementB より前なので、
89    // 結果としては DOCUMENT_POSITION_FOLLOWING (elementBがelementAの後に来る)と
90    // DOCUMENT_POSITION_PRECEDING (elementAがelementBより前) が混同しやすい。
91    // 正しくは、「比較対象ノード (elementB) が、現在のノード (elementA) の前に来るかどうか」を見る。
92    // 実際には、$elementA->compareDocumentPosition($elementB) は
93    // $elementB が $elementA の後に来るため、DOCUMENT_POSITION_FOLLOWING フラグが立つ。
94    // 「elementA は elementB より前に現れる」という関係は、
95    // $elementB->compareDocumentPosition($elementA) で DOCUMENT_POSITION_PRECEDING となる。
96    // ここでは、`$elementA` の視点から `$elementB` がどう見えるかを記述します。
97    if ($positionResult & Dom\Node::DOCUMENT_POSITION_FOLLOWING) {
98        echo "  - elementA より elementB は文書上で後に現れます (FOLLOWING).\n";
99        echo "    (これは、elementA が elementB より前に現れることを意味します).\n";
100    }
101    echo "\n";
102
103    // --------------------------------------------------------------------------------
104    // 例4: 異なる親を持つノード間の比較
105    echo "4. elementA と siblingC の比較 (異なる親を持つノード)\n";
106    // elementA が siblingC と比べてどこに位置するかを比較
107    $positionResult = $elementA->compareDocumentPosition($siblingC);
108    echo "  結果のビットマスク (int): " . $positionResult . "\n";
109
110    // Dom\Node::DOCUMENT_POSITION_DISCONNECTED 定数を使用して、
111    // ノード間に直接的な親子関係がないかをチェック
112    if ($positionResult & Dom\Node::DOCUMENT_POSITION_DISCONNECTED) {
113        echo "  - elementA と siblingC は直接的な親子関係がありません (DISCONNECTED).\n";
114    }
115    // elementA が siblingC より文書上で前に現れるかをチェック
116    if ($positionResult & Dom\Node::DOCUMENT_POSITION_PRECEDING) {
117        echo "  - elementA は siblingC より文書上で前に現れます (PRECEDING).\n";
118    }
119    // 実装依存のフラグが存在する場合
120    if ($positionResult & Dom\Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC) {
121        echo "  - 実装依存のフラグが設定されています (IMPLEMENTATION_SPECIFIC).\n";
122    }
123    echo "\n";
124
125    // --------------------------------------------------------------------------------
126    // 例5: 同じノードの比較
127    echo "5. elementA と elementA 自身の比較\n";
128    // 同じノードを比較した場合、結果は0(差異なし)になる
129    $positionResult = $elementA->compareDocumentPosition($elementA);
130    echo "  結果のビットマスク (int): " . $positionResult . "\n";
131    if ($positionResult === 0) {
132        echo "  - ノードは同じです (差異なし: 0).\n";
133    }
134    echo "\n";
135
136    echo "--- Dom\\Node クラスの比較関連定数の値 ---\n";
137    echo "Dom\\Node::DOCUMENT_POSITION_DISCONNECTED: " . Dom\Node::DOCUMENT_POSITION_DISCONNECTED . "\n";
138    echo "Dom\\Node::DOCUMENT_POSITION_PRECEDING:    " . Dom\Node::DOCUMENT_POSITION_PRECEDING . "\n";
139    echo "Dom\\Node::DOCUMENT_POSITION_FOLLOWING:    " . Dom\Node::DOCUMENT_POSITION_FOLLOWING . "\n";
140    echo "Dom\\Node::DOCUMENT_POSITION_CONTAINS:     " . Dom\Node::DOCUMENT_POSITION_CONTAINS . "\n";
141    echo "Dom\\Node::DOCUMENT_POSITION_CONTAINED_BY: " . Dom\Node::DOCUMENT_POSITION_CONTAINED_BY . "\n";
142    echo "Dom\\Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC: " . Dom\Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC . "\n";
143}
144
145// 上記のデモンストレーション関数を実行
146demonstrateDomNodePositionComparison();
147
148?>

PHP 8のDOM拡張機能において、Dom\Node::compareDocumentPositionメソッドはDOM文書内の2つのノード間の位置関係を比較します。このメソッドは、比較対象のDom\Nodeオブジェクトを引数にとり、ノード間の様々な関係を示すint型のビットマスクを戻り値として返します。

このビットマスクには、例えば現在のノードが比較対象ノードに包含されている(子孫である)場合にセットされるDom\Node::DOCUMENT_POSITION_CONTAINED_BYや、比較対象ノードが現在のノードより文書上で前に現れる場合にセットされるDom\Node::DOCUMENT_POSITION_PRECEDINGといった定数(フラグ)が含まれます。リファレンス情報ではDom\EntityReferenceに属するとされていますが、これらの定数は実際にはDom\Nodeクラスで利用されます。

サンプルコードは、簡潔なHTMLをロードし、複数のノード間でcompareDocumentPositionメソッドを用いて位置関係を比較する具体例を示しています。戻り値のビットマスクを上記の定数とビット演算子(&)で照合することで、DOMツリーにおけるノードの正確な位置関係を判断する方法を学ぶことができます。これは、DOM操作における要素の動的な配置や検証ロジックを実装する上で重要な機能です。

このサンプルコードは、DOMツリーにおけるノード間の位置関係をcompareDocumentPositionメソッドで比較する具体的な例です。このメソッドは、複数の状態を同時に表すビットマスク整数を戻り値として返すため、特定の状態を確認する際にはビットAND演算子(&)を使用する必要がある点にご注意ください。特にDOCUMENT_POSITION_PRECEDINGDOCUMENT_POSITION_FOLLOWINGの定数は、比較対象のノードが基準となるノードに対して文書上で「前に現れるか、後に現れるか」を示すため、どちらのノードを基準に比較しているかによって意味合いが変わることを理解しておくことが重要です。リファレンス情報では定数がDom\EntityReferenceクラスに記載されていますが、実際にはこれらの定数や比較メソッドはDom\Nodeクラスに定義されており、継承関係によって利用されています。また、getElementByIdなどの要素取得メソッドは、対象要素が見つからない場合にnullを返すため、比較処理を行う前にノードが正しく取得できているか常に確認するようにしてください。

DOMノードの包含関係を比較する

1<?php
2
3/**
4 * DOMノードの位置関係を比較する例。
5 * Dom\Node::compareDocumentPosition() メソッドと、その戻り値を解析するための
6 * Dom\Node::DOCUMENT_POSITION_CONTAINED_BY 定数の使用方法を示します。
7 *
8 * PHP 8では、DOMの位置関係定数(例: DOCUMENT_POSITION_CONTAINED_BY)は、
9 * Dom\EntityReferenceを含むほとんどのDOMノードが継承するDom\Nodeクラスに定義されています。
10 * したがって、Dom\Node::定数としてアクセスするのが一般的です。
11 *
12 * @return void
13 */
14function demonstrateDomNodeContainmentComparison(): void
15{
16    // 新しい DOM ドキュメントを作成します。
17    $document = new DOMDocument();
18
19    // ルート要素として 'parent' を作成し、ドキュメントに追加します。
20    $parentElement = $document->createElement('parent');
21    $document->appendChild($parentElement);
22
23    // 子要素として 'child' を作成し、親要素に追加します。
24    $childElement = $document->createElement('child');
25    $parentElement->appendChild($childElement);
26
27    // ドキュメントに追加しますが、親要素とは異なる階層にある独立した要素 'other' を作成します。
28    $otherElement = $document->createElement('other');
29    $document->appendChild($otherElement);
30
31    echo "--- DOM ノードの位置関係の比較例 ---\n\n";
32
33    // ------------------------------------------------------------------------------------------------
34    // 1. childElement (呼び出し元) と parentElement (引数) の位置関係の比較
35    //    期待される結果: childElement は parentElement に包含されている
36    // ------------------------------------------------------------------------------------------------
37    echo "比較: \$childElement->compareDocumentPosition(\$parentElement)\n";
38    $positionChildVsParent = $childElement->compareDocumentPosition($parentElement);
39    echo "  戻り値: " . $positionChildVsParent . " (ビットマスク)\n";
40
41    // DOCUMENT_POSITION_CONTAINED_BY: 呼び出し元のノードが、引数のノードに包含されている (内部にある) 場合。
42    if (($positionChildVsParent & Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) === Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) {
43        echo "  結果: childElement は parentElement に包含されています。\n";
44    } else {
45        echo "  結果: childElement は parentElement に包含されていません。\n";
46    }
47
48    // DOCUMENT_POSITION_CONTAINS: 呼び出し元のノードが、引数のノードを包含している (親である) 場合。
49    if (($positionChildVsParent & Dom\Node::DOCUMENT_POSITION_CONTAINS) === Dom\Node::DOCUMENT_POSITION_CONTAINS) {
50        echo "  結果: childElement は parentElement を包含しています。\n";
51    } else {
52        echo "  結果: childElement は parentElement を包含していません。\n";
53    }
54    echo "\n";
55
56    // ------------------------------------------------------------------------------------------------
57    // 2. parentElement (呼び出し元) と childElement (引数) の位置関係の比較 (順序を逆にした場合)
58    //    期待される結果: parentElement は childElement を包含している
59    // ------------------------------------------------------------------------------------------------
60    echo "比較: \$parentElement->compareDocumentPosition(\$childElement)\n";
61    $positionParentVsChild = $parentElement->compareDocumentPosition($childElement);
62    echo "  戻り値: " . $positionParentVsChild . " (ビットマスク)\n";
63
64    if (($positionParentVsChild & Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) === Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) {
65        echo "  結果: parentElement は childElement に包含されています。\n";
66    } else {
67        echo "  結果: parentElement は childElement に包含されていません。\n";
68    }
69
70    if (($positionParentVsChild & Dom\Node::DOCUMENT_POSITION_CONTAINS) === Dom\Node::DOCUMENT_POSITION_CONTAINS) {
71        echo "  結果: parentElement は childElement を包含しています。\n";
72    } else {
73        echo "  結果: parentElement は childElement を包含していません。\n";
74    }
75    echo "\n";
76
77    // ------------------------------------------------------------------------------------------------
78    // 3. childElement (呼び出し元) と otherElement (引数) の位置関係の比較 (独立した要素間)
79    //    期待される結果: 互いに包含関係がなく、切断されている
80    // ------------------------------------------------------------------------------------------------
81    echo "比較: \$childElement->compareDocumentPosition(\$otherElement)\n";
82    $positionChildVsOther = $childElement->compareDocumentPosition($otherElement);
83    echo "  戻り値: " . $positionChildVsOther . " (ビットマスク)\n";
84
85    if (($positionChildVsOther & Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) === Dom\Node::DOCUMENT_POSITION_CONTAINED_BY) {
86        echo "  結果: childElement は otherElement に包含されています。\n";
87    } else {
88        echo "  結果: childElement は otherElement に包含されていません。\n";
89    }
90
91    if (($positionChildVsOther & Dom\Node::DOCUMENT_POSITION_CONTAINS) === Dom\Node::DOCUMENT_POSITION_CONTAINS) {
92        echo "  結果: childElement は otherElement を包含しています。\n";
93    } else {
94        echo "  結果: childElement は otherElement を包含していません。\n";
95    }
96
97    // DOCUMENT_POSITION_DISCONNECTED: 2つのノードが同じドキュメントツリー内にないか、または親子関係にない場合に設定されます。
98    if (($positionChildVsOther & Dom\Node::DOCUMENT_POSITION_DISCONNECTED) === Dom\Node::DOCUMENT_POSITION_DISCONNECTED) {
99        echo "  結果: childElement と otherElement は互いに切断されています。\n";
100    } else {
101        echo "  結果: childElement と otherElement は切断されていません。\n";
102    }
103    echo "\n";
104}
105
106// 関数を実行して、DOMノードの位置関係の比較結果を表示します。
107demonstrateDomNodeContainmentComparison();

PHPのDom\Node::DOCUMENT_POSITION_CONTAINED_BYは、DOM(Document Object Model)におけるノード間の位置関係を示す整数型の定数です。この定数は、あるノードが別のノードに「包含されている」、つまりその内部に存在している状態を表します。主にDom\Node::compareDocumentPosition()メソッドの戻り値を解析する際に利用されます。

Dom\Node::compareDocumentPosition()メソッドは、呼び出し元のノードと引数で指定したノードとの間の相対的な位置関係を、ビットマスク形式の整数値として返します。この戻り値は、複数の位置関係を示すフラグが同時に含まれる場合があるため、DOCUMENT_POSITION_CONTAINED_BYのような定数とビットAND演算(&)を用いて、特定の関係が成立しているかを判定します。

サンプルコードでは、親要素と子要素、および全く関係のない独立した要素を作成し、それぞれのノード間でcompareDocumentPosition()を実行しています。例えば、子要素を呼び出し元とし、親要素を引数として比較した場合、戻り値にDOCUMENT_POSITION_CONTAINED_BYのフラグが含まれることで、子要素が親要素に包含されていることがわかります。また、呼び出し元が引数を包含するDOCUMENT_POSITION_CONTAINSや、互いに独立しているDOCUMENT_POSITION_DISCONNECTEDといった関連する定数と比較することで、より詳細な位置関係を判別できることを示しています。このように、この定数はDOMツリー内でのノードの構造的な位置をプログラムで確認するのに役立ちます。

この定数は、Dom\Node::compareDocumentPosition() メソッドの戻り値(ビットマスク)を解析する際に用います。複数の状態が同時に設定されるため、特定の状態を判別するには必ずビット論理積 (&) 演算子を使用してください。単純な等値比較 (==) は意図しない結果を招く可能性があります。リファレンスではDom\EntityReferenceに記載されていますが、実際にはDom\Nodeクラスの定数としてアクセスするのが一般的です。DOCUMENT_POSITION_CONTAINED_BYは「呼び出し元が引数に包含されている」ことを、DOCUMENT_POSITION_CONTAINSは「呼び出し元が引数を包含している」ことを示すため、混同しないようにご注意ください。

関連コンテンツ

関連プログラミング言語