I want extend class which have final constructor (in my case it\'s SimpleXMLElement), but i have problems because when i use:
class myclass extends Simpl
There can be valid reasons to extend a third-party "final" class, resulting in more readable/maintainable code than completely duplicating it or creating some convoluted work-around. And certainly preferable over changing the third-party source code and removing the "final" keyword.
PHP supplies the extension "Componere" to accomplish such a feat in those rare cases where it truly is the best option. Below an example that shows how a the child class can be defined as a "trait", which can then be used to dynamically extend a final parent class:
<?php
declare(strict_types=1);
/*
* Final class would normally prevent extending.
*/
final class ParentC
{
public $parentvar;
public $secondvar;
function __construct() { echo( "\r\n<br/>".$this->parentvar = 'set by '.get_class().'->parentconstruct' ); }
function parentf() { echo( "\r\n<br/>".get_class().'->parentf >> '.$this->parentvar ); }
}
/*
* Extended class members.
*/
trait ChildC /* extends ParentC */
{
function __construct() {
// Call parent constructor.
parent::__construct();
// Access an inherited property set by parent constructor.
echo( "\r\n<br/>".get_class().'->overridden_constructor >> '.$this->parentvar );
}
function parentf() {
// Call overridden parent method.
parent::parentf();
// Access an inherited property set by constructor.
echo( "\r\n<br/>".get_class().'->overridden_parentf >> '.$this->parentvar );
}
function dynamicf( $parm = null ) {
// Populate a parent class property.
$this->secondvar = empty( $parm ) ? 'set by '.get_class().'->dynamicf' : $parm;
// Access an inherited property set by parent constructor.
echo( "\r\n<br/>".get_class().'->dynamicf >> '.$this->parentvar );
}
}
/*
* Register the dynamic child class "ChildC", which is
* derived by extending "ParentC" with members supplied as "ChildC" trait.
*/
$definition = new \Componere\Definition( 'ChildC', ParentC::class );
$definition->addTrait( 'ChildC' );
$definition->register();
/*
* Instantiate the dynamic child class,
* and access its own and inherited members.
*/
$dyno = new ChildC;
$dyno->parentf();
$dyno->dynamicf( 'myvalue ');
// Our object is also recognized as instance of parent!
var_dump( $dyno instanceof ChildC, $dyno instanceof ParentC, is_a( $dyno, 'ParentC') );
var_dump( $dyno );
?>
Well, final
means final. No overriding the method. Even if you ask nicely. I suggest adding a static make() method to your new class. Something like:
class myclass extends SimpleXMLElement {
static function make($data, $xmlVersion='1.0', $xmlEncoding='ISO-8859-1', $rootName='root'){
$obj=parent::__construct($data);
$obj->x=$xmlVersion;
$obj->e=$xmlEncoding;
$obj->r=$rootName;
return $obj;
}
}
I would use Delegate wrapper design in this case. You should consider composition instead of inheritance here.
I just went through this exact thing. You don't need to extend it. Make a class that holds SimpleXMLElement objects. I believe this is what Nikola meant.
class XmlResultSet
{
public $xmlObjs = array();
public function __construct(array $xmlFiles)
{
foreach ($xmlFiles as $file) {
$this->xmlObjs[] = new XmlResult($file);
}
}
}
class XmlResult
{
private $xmlObj;
public function __construct($file)
{
try {
$this->xmlObj = new SimpleXMLElement($file, 0, true);
}
catch (Exception $e) {
throw new MyException("Invalid argument ($this)($file)(" . $e .
")", PHP_ERRORS);
}
}
public function otherFunctions()
{
return $this->xmlObj->movie['name']; // whatever
}
}
I know this is an old post but I had a similar problem just now. I was actually including the same class file twice. Use include_once() or require_once() instead of include() or require().
class myclass extends SimpleXMLElement {
public static function getInstance($xmlversion = '1.0', $xmlencoding = 'ISO-8859-1', $rootName='root') {
return new self("<?xml version='$xmlVersion' encoding='$xmlEncoding'?><$rootName />");
}
}