【PHP8.x】firstChildプロパティの使い方

firstChildプロパティの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

firstChildプロパティは、Dom\CharacterDataクラスに属し、そのノードの最初の子ノードを保持するプロパティです。Dom\CharacterDataクラスは、PHPのDOM拡張機能において、XMLやHTMLドキュメント内で文字データを直接保持するノードの基底クラスとして定義されています。具体的には、テキストノード(要素間の文字列)、コメントノード(<!-- ... -->)、そしてCDATAセクションノード(<![CDATA[ ... ]]>)などがこのクラスのサブタイプにあたります。

一般的なDOMノード、例えば要素ノード(<div><p>など)の場合、firstChildプロパティは、そのノードが持つ子ノードのリストの中から、最初に位置する子ノードへの参照を返します。これにより、ドキュメントツリー構造をたどり、特定のノードの子要素やテキストにアクセスする際に利用されます。もし対象のノードに子ノードが一つも存在しない場合は、このプロパティはnullを返します。

しかし、Dom\CharacterDataクラスのインスタンスであるテキストノードやコメントノードは、それ自体が直接文字データの内容を保持する特殊なノードです。これらのノードはDOMの構造上、それ自身の内部にさらに別の子ノードを持つことはありません。例えば、「Hello World」というテキストノードは、その文字列自体がノードの「値」であり、その文字列の中に別のDOMノードが埋め込まれているわけではないため、子ノードが存在しないという特性を持っています。

したがって、Dom\CharacterDataクラスのオブジェクトに対してfirstChildプロパティにアクセスした場合、結果は常にnullとなります。これは、Dom\CharacterData型のノードがDOMツリーにおいて「葉ノード」(末端ノード)として振る舞い、子ノードを持たないという設計上の特性によるものです。これらのノードが保持する実際の文字データにアクセスするには、firstChildプロパティではなく、dataプロパティやnodeValueプロパティを使用する必要があることに注意してください。

構文(syntax)

1<?php
2
3$dom = new DOMDocument();
4$characterDataNode = $dom->createTextNode("Sample text content.");
5
6// Dom\CharacterData::firstChild プロパティにアクセス
7// CharacterData ノードは子ノードを持たないため、このプロパティは常に null を返します。
8$first = $characterDataNode->firstChild;
9
10var_dump($first);
11
12?>

引数(parameters)

引数なし

引数はありません

戻り値(return)

Dom\Node|null

このプロパティは、現在のノードの最初の子ノードを表す Dom\Node オブジェクト、または子ノードが存在しない場合は null を返します。

サンプルコード

Dom\CharacterDatafirstChildは常にnullを返す

1<?php
2
3/**
4 * Dom\CharacterData::firstChild プロパティの動作を示す関数。
5 * Dom\CharacterData は、DOMツリーにおけるテキストやコメントなどの文字データを表す抽象クラスです。
6 * DOMText や DOMComment などがこのクラスを継承します。
7 * これらのノードは子ノードを持つことができないため、firstChild プロパティは常に null を返します。
8 */
9function demonstrateDomCharacterDataFirstChild(): void
10{
11    // DOMText は Dom\CharacterData を継承する具体的なクラスです。
12    // テキストノードを作成します。
13    $textNode = new DOMText("これはサンプルテキストです。");
14
15    echo "--- Dom\\CharacterData (DOMText) の firstChild プロパティ ---" . PHP_EOL;
16    echo "作成したテキストノードの内容: '" . $textNode->nodeValue . "'" . PHP_EOL;
17
18    // Dom\CharacterData を継承するノード (DOMTextなど) は、構造上、子ノードを持つことができません。
19    // したがって、その firstChild プロパティは常に null を返します。
20    $firstChild = $textNode->firstChild;
21
22    // firstChild の値を出力します。null が表示されるはずです。
23    echo "テキストノードの firstChild プロパティの値: " . var_export($firstChild, true) . PHP_EOL;
24
25    // null であることを明示的に確認し、初心者にも理解しやすいメッセージを出力します。
26    if ($firstChild === null) {
27        echo "上記の結果から、Dom\\CharacterData (DOMText) の firstChild プロパティは期待通り null であることがわかります。" . PHP_EOL;
28        echo "これは、テキストノード自体が子ノードを持つ構造ではないためです。" . PHP_EOL;
29    } else {
30        echo "エラー: Dom\\CharacterData (DOMText) の firstChild プロパティが null ではありませんでした。" . PHP_EOL;
31    }
32}
33
34// 関数を実行して、Dom\CharacterData::firstChild の動作を確認します。
35demonstrateDomCharacterDataFirstChild();

Dom\CharacterData::firstChild プロパティは、PHPのDOM拡張機能の一部で、Dom\CharacterDataクラスに属します。Dom\CharacterDataは、XMLやHTMLのDOMツリーにおいて、テキストやコメント、CDATAセクションといった文字データを扱うための抽象クラスです。例えば、具体的なテキストノードを表すDOMTextクラスなどがこのDom\CharacterDataを継承します。

通常、firstChildプロパティは、親ノードの最初の子ノードを取得するために使われます。しかし、Dom\CharacterDataを継承するノード、つまりテキストやコメントノード自体は、その構造上、自身の中にさらに子ノードを持つことができません。そのため、Dom\CharacterData::firstChild プロパティにアクセスしても、常にnullが戻り値として返されます。戻り値の型がDom\Node|nullとなっているのは、子ノードが存在しない場合にnullが返されることを示しています。

サンプルコードでは、DOMTextクラスのインスタンスを作成し、そのfirstChildプロパティが実際にnullを返すことを確認しています。これにより、テキストノードが子ノードを持たないという特性を、具体的なコードの動作を通して理解することができます。DOMツリーを扱う際には、このようなノードの特性を把握しておくことが重要です。

このサンプルコードは、Dom\CharacterDataクラスのfirstChildプロパティの動作を示しています。Dom\CharacterDataは、テキストやコメントなど、文字データのみを保持するノードの抽象クラスです。これらのノードはDOMツリーの構造上、子ノードを持つことができません。そのため、Dom\CharacterDataを継承するDOMTextなどのインスタンスに対してfirstChildプロパティにアクセスすると、常にnullが返されます。これはエラーではなく、このクラスの正しい挙動です。他の要素ノード(例: DOMElement)のように子ノードが返されることを期待すると、意図しない動作となるため注意してください。nullが返ってくることを前提に、コードを安全に記述することが大切です。

PHP DOM Document firstChildで最初の子ノードを取得する

1<?php
2
3/**
4 * DOMElementのfirstChildプロパティを使用して最初の子ノードを取得するサンプル関数
5 *
6 * firstChildプロパティは、指定されたノードの最初の子ノードを返します。
7 * 子ノードが存在しない場合は null を返します。
8 * この例では、<p>要素の最初の子ノードであるテキストノードを取得します。
9 * テキストノード (DOMText) は CharacterData クラスを継承しています。
10 */
11function showFirstChildExample(): void
12{
13    // HTML文字列を定義
14    $html = '<!DOCTYPE html>
15    <html>
16    <body>
17        <div id="container">
18            <p>これは最初の段落です。</p>
19            <p>これは二番目の段落です。</p>
20        </div>
21    </body>
22    </html>';
23
24    // DOMDocumentオブジェクトをインスタンス化
25    $dom = new DOMDocument();
26
27    // HTMLを読み込む (エラーを抑制)
28    // HTML5の要素を正しく解釈させるため、内部エラーを無効化
29    libxml_use_internal_errors(true);
30    $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
31    libxml_clear_errors();
32
33
34    // IDで要素を取得
35    $container = $dom->getElementById('container');
36
37    if ($container) {
38        // コンテナ要素の最初の子要素 (<p>要素) を取得
39        // firstChild はテキストノードやコメントノードも含むため、
40        // 要素のみを対象とする場合は firstElementChild を使用します。
41        // ここではfirstChildの動作を確認するため、あえてこのプロパティを使用します。
42        // <div id="container"> と <p> の間には改行などによるテキストノードが存在する可能性があります。
43        $firstNode = $container->firstChild;
44
45        // 最初の子がテキストノード(空白や改行)である可能性を考慮し、次の要素を取得
46        $firstParagraph = $firstNode->nextElementSibling;
47
48        if ($firstParagraph instanceof DOMElement) {
49            // <p>要素の最初の子ノード(テキストノード)を取得
50            $textNode = $firstParagraph->firstChild;
51
52            // 取得したノードがテキストノード (DOMText) であることを確認
53            // DOMText は Dom\CharacterData を継承しています
54            if ($textNode instanceof DOMText) {
55                echo "取得したノードの型: " . get_class($textNode) . PHP_EOL;
56                echo "ノードの値: " . $textNode->nodeValue . PHP_EOL;
57            } else {
58                echo "<p>要素の最初の子ノードはテキストノードではありませんでした。" . PHP_EOL;
59            }
60        } else {
61            echo "最初の<p>要素が見つかりませんでした。" . PHP_EOL;
62        }
63    } else {
64        echo "ID 'container' の要素が見つかりませんでした。" . PHP_EOL;
65    }
66}
67
68// サンプル関数を実行
69showFirstChildExample();

firstChildは、あるノードが持つ最初の子ノードを取得するためのプロパティです。ここでの子ノードとは、HTMLタグのような「要素ノード」だけでなく、単なる文字列である「テキストノード」やコメントなども含みます。もし対象のノードに子ノードが一つも存在しない場合は、nullを返します。このプロパティに引数はありません。

このサンプルコードでは、まずHTML文字列を解析し、特定の<p>要素(段落)を取得します。次に、その<p>要素に対してfirstChildプロパティを呼び出し、最初の子ノードを取得しています。この場合、<p>これは最初の段落です。</p>という構造なので、取得されるのは「これは最初の段落です。」という文字列を表すテキストノード(DOMTextオブジェクト)です。DOMTextDom\CharacterDataクラスの一種です。最後に、取得したテキストノードが持つnodeValueプロパティを利用して、実際の文字列を画面に出力しています。このように、要素が内包する最初のコンテンツにアクセスする際にfirstChildプロパティは役立ちます。

firstChildプロパティは、要素だけでなく、HTMLソースコード上の改行や空白文字からなるテキストノードも最初の子ノードとして取得する点に注意が必要です。そのため、必ずしも期待した要素が取得できるとは限りません。要素ノードのみを確実に取得したい場合は、代わりにfirstElementChildプロパティの使用を検討してください。また、子ノードが存在しない場合はnullを返すため、取得した値を使用する前には必ずif文などでnullでないことを確認する必要があります。この確認を怠ると、エラーの原因となります。