私たちはPHP7を使用しているとします(上記の動作は少なくともPHPバージョン5.7に特有です)。
DOMNode::appendChild
方法は、新しいDOMNode
オブジェクトの内部構造を設定します(我々の場合には、それはDOMDocument
オブジェクトの)親ノードの内部構造を更新し、その後、作成され、準備された内部構造に基づいて新しいDOMNode
オブジェクトを返します。実際に返されたオブジェクトおよび添付の子ノードのオブジェクトは同じです:
$ret_node = $doc->appendChild($node);
debug_zval_dump($node);
debug_zval_dump($ret_node);
var_dump(spl_object_hash($node));
var_dump(spl_object_hash($ret_node));
出力:
object(myDOMElement)#2 (18) refcount(3){
..
object(myDOMElement)#2 (18) refcount(3){
...
string(32) "00000000121277ac00000000658254f1"
string(32) "00000000121277ac00000000658254f1"
DOMNode::$childNodes
プロパティ読みハンドラはDOMNodeList
イテレータオブジェクトを作成します。現在のイテレータ値is fetchedはzval
からphp_dom_iterator_move_forward
で作成されています。後者は内部XML構造に基づいて"creates new object"(特にDOMNode
) のみです。
しかし、方法はphp_dom_create_object
オブジェクトを作成するトリッキーです!
php_libxml_increment_node_ptr((php_libxml_node_object *)intern, obj, (void *)intern);
次回それが呼び出しphp_dom_create_object
それdetects the saved pointer, increments reference count, and returns the previously created object:
if ((intern = (dom_object *) php_dom_object_get_data((void *) obj))) {
GC_REFCOUNT(&intern->std)++;
ZVAL_OBJ(return_value, &intern->std);
return 1;
}
フリーオブジェクトハンドラで(と呼ばれるオブジェクトが最初に構築される場合、それはphp_libxml_increment_node_ptr
によってポインタを保存しますオブジェクトが破棄されている)DOM拡張子callsphp_libxml_decrement_node_ptr
。
私たちが見る通り、DOMオブジェクトは実際にはPHP変数の長さのままです。変数が有効範囲外になると、変数は破棄されます。この場合、DOM拡張は私たちのために新しいオブジェクトを生成します。
今度はmyDOMElement
クラスにデストラクタを追加してみましょう。
class myDOMElement extends DOMElement
{
public $myProp = 'Some default';
public function __destruct() {
echo __METHOD__, PHP_EOL;
}
}
その後、次のコードは、DOMNode
オブジェクトが、我々はそれに$doc->createElement('b')
を割り当てるラインで破壊されていることが表示されます:
$node = $doc->createElement('a');
$node->myProp = 'A';
$doc->appendChild($node);
echo "Marker B-1\n";
$node = $doc->createElement('b');
echo "Marker B-2\n";
$node->myProp = 'B';
$doc->appendChild($node);
出力:
Marker B-1
myDOMElement::__destruct
Marker B-2
DOM拡張機能自体にzval
オブジェクトが格納されていないため、変数$node
に格納されていた以前のオブジェクトは範囲外になり、自動的に破棄されます。これからPHPオブジェクトへの参照はありません。それはまた、myProp
のプロパティも破壊されています。
foreach ($doc->childNodes as $n) {
var_dump($n->tagName);
}
したがって、あなたの質問
への答えは、なぜ私は「得るか:しかし、DOM拡張は、我々はループの中でそれを要求した場合、a
ノードに対して新しいインスタンスを生成します。値 "A"の代わりにタグaのデフォルト値 "?
は次のとおりです。$myProp = "A"
を持つオブジェクトが実際に破壊され、あなたが$node
変数に別のオブジェクトを割り当てるときに、それはスコープの外に出ると、DOM拡張が私たちのためにPHPのオブジェクトを格納していないため - それは、デリゲートこの責任にユーザー。ただし、ノードはまだ内部DOM構造に存在しています。したがって、ループ内のA
タグになると、DOM拡張機能はデフォルトのプロパティを持つ新しいオブジェクトを生成します。この質問は関連している可能性があり
foreach (['a', 'b'] as $name) {
$nodes[] = $node = $doc->createElement($name);
$node->myProp = $name;
$doc->appendChild($node);
}
foreach ($doc->childNodes as $n) {
echo 'Tag ', $n->tagName, ' myProp:'; var_dump($n->myProp);
}
unset($nodes);
出力
Tag a myProp:string(1) "a"
Tag b myProp:string(1) "b"
:http://stackoverflow.com/q/5473967ため –