ID: 35104 User updated by: php at tjworld dot net Reported By: php at tjworld dot net Status: Assigned Bug Type: Class/Object related Operating System: Windows 2003 PHP Version: 5.1.0RC5 Assigned To: dmitry New Comment:
Thanks for the DOM-specific recommendations, I'll have a play about with it. The case for dynamic properties is a big issue in itself, since when extending a class the developer doesn't always have control of the internal design on the super-class. This could lead to some frustrating situations where the developer has every reasonable expectation they can extend the super-class, but in use trying to modify a protected or public property causes this Fatal Error. It could also lead to intermitent results if the statement attempting the modification is in a little-used method of the sub-class, and only occurs on rare occasions. Without compile-time access-checking (unlike a strongly typed pre-compiled environment) these kind of issues could occur easily, especially for the more general developers who aren't so au-fait with the technicalities of PHP OO dynamic properties. I was wondering if the properties affected by __set() should be marked final, which would prevent inconsistencies but reduce functionality to a great extent. Maybe its a case of stressing in the documentation *not* to rely on __set() to produce read-only properties *unless* the __set() method first checks that the calling class-instance is an instanceof the super-class - in other words the read-only functionality is conditional on the method being called on an instance of the super-class itself, not a sub-class. This puts the ball back in the developer's court, but you'd need some good strong documentation across the platform to ensure developers use this design template. Previous Comments: ------------------------------------------------------------------------ [2005-11-04 22:54:02] [EMAIL PROTECTED] Cant say about other internal classes, but DOM is written specifically not to allow overriding properties (properties provide direct access to libxml2 functionality which cant be done in userland). As far as casting goes... already working on a way to allow returning extended classes from all functions in dom (for PHP 6). Current workaround for your issue create your extended class using new keyword, and append it to a DOMDocumentFragment (if you dont want it linked into the document tree) that was created using createDocumentFragment. The appending updates the libxml2 pointers and the extended object is now linked to the DOMDocument correctly. Was this report specific to dom or is it to remain open for the extneded uses object example? ------------------------------------------------------------------------ [2005-11-04 21:39:48] php at tjworld dot net "but DOM properties CANNOT be overriden." Does this occur anywhere else in the PHP classes or is it unique to DOM? It's the first time I've met this situation in OO since the 80's. It pretty much makes having the DOM object-oriented pointless, when the base class (DOMNode) of the other significant DOM classes prevents useful extension. A simple solution would be to provide a courtesy: DOMNode->__construct($ownerDocument = null); But that'd be available to the public of course. Alternatively, protected DOMNode function _setOwnerDocument(DOMDocument ownerDocument); But thats a bit arbitary. Alternatively, solve the practical loss of functionality by fixing the bug in importNode() so it returns an object of the class passed in: DOMNode DOMDocument->importNode(DOMNode $node, bool deep); Currently it *casts* the passed $node to one of the DOM base classes it inherited from *and* discards all their extended properties and methods, which is surely not OO behaviour because in the following scenario, the cases listed at the end are inconsistent: class inChild extends DOMNode {} class inGrandChild extends DOMElement() class inGreatGrandChild extends inGrandChild() $node = new DOMNode(); $element = new DOMElement(); $child = new inChild(); $grandChild = new inGrandChild(); $greatGrandChild = new inGreatGrandChild(); 1. DOMDocument->importNode($node, true) instanceof DOMNode 2. DOMDocument->importNode($element, true) instanceof DOMElement 3. DOMDocument->importNode($child, true) instance of DOMNode 4. DOMDocument->importNode($grandChild, true) instanceof DOMElement (not inGrandChild) 5. DOMDocument->importNode($greatGrandChild, true) instanceof DOMElement (not inGreatGrandChild) So importNode() doesn't even cast to a consistent DOMNode, but to the 'highest* level in the built-in classes. Usually in OO although the cast is to a super-class (to guarantee portability) the extended methods and properties aren't discarded. If importNode() were fixed to return the same class as passed in the following code would solve the ownerDocument issue: <?php class extDOMDocument extends DOMDocument { public function createElement($name, $value=null) { $orphan = new extDOMElement($name, $value); $adopt = $this->importNode($ret, true); // adopt it // now $adopt satisfies $this->isSameNode($adopt->ownerDocument) && $adopt instanceof extDOMelement return $adopt; } } class extDOMElement extends DOMElement { function __construct($name, $value=null, $namespace=null) { parent::__construct($name, $value, $namespaceURI); } // ... more class definition here } (excuse any typo's - working weird hours!) ------------------------------------------------------------------------ [2005-11-04 17:02:40] [EMAIL PROTECTED] I can't speak for the user class example, but DOM properties CANNOT be overriden. ------------------------------------------------------------------------ [2005-11-04 16:26:34] [EMAIL PROTECTED] Dmitry, any insight on this? ------------------------------------------------------------------------ [2005-11-04 13:27:28] php at tjworld dot net Further test using DOMDocument/DOMElement... C:\PHP\5.1.0RC5-dev>php.exe dom.php Fatal error: extDOMElement::__construct(): Cannot write property in C:\dom.php on line 14 ----------dom.php------------- <?php class extDOMDocument extends DOMDocument { public function createElement($name, $value=null) { $ret = new extDOMElement($name, $value, $this); // create the new element with this Document as owner return $ret; } } class extDOMElement extends DOMElement { function __construct($name, $value='', $owner=null, $namespaceURI=null) { if(!$owner instanceof extDOMDocument) throw new DOMException(DOM_NOT_FOUND_ERR); // illegal owner parent::__construct($name, $value, $namespaceURI); $this->ownerDocument = $owner; //** this line causes a Fatal Error } // ... more class definition here } $doc = new extDOMDocument('test'); $el = $doc->createElement('tagname'); ?> ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/35104 -- Edit this bug report at http://bugs.php.net/?id=35104&edit=1