Edit report at http://bugs.php.net/bug.php?id=52782&edit=1
ID: 52782
Comment by: bugs dot php dot net at moesen dot nu
Reported by: bugs dot php dot net at moesen dot nu
Summary: DOMDocument subclass forgotten using ->ownerDocument
after closure
Status: Open
Type: Bug
Package: DOM XML related
Operating System: GNU/Linux 2.6.26-2-686 (Debian)
PHP Version: 5.3SVN-2010-09-06 (snap)
Block user comment: N
New Comment:
(Following up on e-mail correspondance with rrichards at php dot net.)
> It'd most likely due to scoping. If you create an element based on a
> subclass, it will only return the subclass as long as the element's
> object (the DOM wrapper not the underlying XML structure) no longer
> has any references.
>
> There are a couple ways to work around this:
>
> 1 - Always keep the doc object in global scope with at least 1
> reference to it. This really is only needed if you are attaching
> custom data to any custom properties.
This does indeed work around the problem, but I am not keen on polluting
the global namespace.
> 2 - The best way is to use: bool DOMDocument::registerNodeClass (
> string $baseclass , string $extendedclass )
> http://us2.php.net/manual/en/domdocument.registernodeclass.php Using
> this mehod, you can register classes to always create specific node
> types with rather than the default DOM classes so if you have any
> custom methods they will always be available i.e.
>
> class myDoc extends DOMDocument { };
>
> $doc = new myDoc();
> $doc->registerNodeClass("DOMDocument", "myDoc");
That works to a certain extent: the class is correct, but its custom
properties are lost, as mentioned in work-around 1. The ownerDocument is
an instance of MyDocument, but instead of being the original instance,
it is a new instance (without calling the constructor) with all of its
properties set to their defaults.
It seems to me that as long as there is a DOMElement, there is an
implicit reference to the original instance of the owner document
(because of $domElement->ownerDocument), so said document should not be
garbage collected.
I have uploaded a simplified test case at http://codepad.org/CBsD3eVp
Previous Comments:
------------------------------------------------------------------------
[2010-09-20 13:19:34] bugs dot php dot net at moesen dot nu
Is there anything I can do to get a confirmation on this? I tried #php
on several networks, but they referred me to Freenode, where #php was
full.
------------------------------------------------------------------------
[2010-09-06 15:43:15] bugs dot php dot net at moesen dot nu
Err, my apologies for not cleaning up the path names. An oversight on my
part.
------------------------------------------------------------------------
[2010-09-06 15:35:59] bugs dot php dot net at moesen dot nu
Description:
------------
We have custom XML document and element classes that extend the original
DOMDocument and DOMElement classes for convenience. There is a class
that uses an instance of XmlElement obtained via a callback specified at
construction time. That XmlElement works fine and stays that way.
However, when we get its ownerDocument outside of the closure, the
result is not an XmlDocument but a DOMDocument. I cannot see a single
reason why.
I tried several options, and it only seems to happen with that closure.
I have checked versions 5.3.1, 5.3.2, 5.3.3 and now the latest 5.3.4
snapshot compiled with './configure && make'.
Test script:
---------------
http://codepad.org/hvrNh86K
The original code uses a lot of namespaces and extends XmlDocument, but
this is a much more minimal test case. Also try the "Uncomment this"
code to see what /does/ work.
Expected result:
----------------
*** Calling the callback directly...
dom-fail.php:110: $container: XmlElement: <div id="content"/>
dom-fail.php:111: $container->ownerDocument: XmlDocument; debug:
object(XmlDocument)#2 (0) refcount(1){
}
*** Calling callback from constructor()...
dom-fail.php:110: $container: XmlElement: <div id="content"/>
dom-fail.php:111: $container->ownerDocument: XmlDocument; debug:
object(XmlDocument)#2 (0) refcount(1){
}
*** In constructor, after check on $container:
dom-fail.php:95: $container: XmlElement: <div id="content"/>
dom-fail.php:96: $container->ownerDocument: XmlDocument; debug:
object(XmlDocument)#2 (0) refcount(1){
}
SUCCESS!
Actual result:
--------------
*** Calling the callback directly...
dom-fail.php:110: $container: XmlElement: <div id="content"/>
dom-fail.php:111: $container->ownerDocument: XmlDocument; debug:
object(XmlDocument)#2 (0) refcount(1){
}
*** Calling callback from constructor()...
dom-fail.php:110: $container: XmlElement: <div id="content"/>
dom-fail.php:111: $container->ownerDocument: XmlDocument; debug:
object(XmlDocument)#2 (0) refcount(1){
}
*** In constructor, after check on $container:
dom-fail.php:95: $container: XmlElement: <div id="content"/>
dom-fail.php:96: $container->ownerDocument: DOMDocument; debug:
object(DOMDocument)#2 (0) refcount(1){
}
PHP Fatal error: Call to undefined method DOMDocument::append() in
/home/jmoe/fuckingpieceofshitfuckfuckfucksocks/dom-fail.php on line 100
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/bug.php?id=52782&edit=1