Extend class with final constructor in PHP

I want to extend a class that has a final constructor (in my case, it is SimpleXMLElement), but I have problems because when I use:

class myclass extends SimpleXMLElement { function __construct($xmlVersion='1.0', $xmlEncoding='ISO-8859-1', $rootName='root'){ parent::__construct("<?xml version='$xmlVersion' encoding='$xmlEncoding'?><$rootName />"); } 

I get an error:

Fatal error: unable to override final method SimpleXMLElement :: __ construct ()

When I remove the constructor, I get this error:

Fatal error: exception for exception "Exception" with the message "SimpleXMLElement :: __ construct () expects at least 1 parameter, 0 when set '

I am missing something or do not understand how to correctly name the parent constructor as final. I do not want the override methods to simply extend the class, but I cannot extend it because it needs __construct (). So I missed something and went back to where I started.

Can someone explain where I was wrong?

+4
php
source share
6 answers

In this case, I would use the delegate shell construct. You should consider composition instead of inheritance here.

+3
source share

I just went through this. You do not need to expand it. Create a class containing SimpleXMLElement objects. I think this is what Nicola had in mind.

 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 } } 
+3
source share
 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 />"); } } 
+2
source share

Well, final means final. Does not cancel the method. Even if you ask beautifully. 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; } } 
+1
source share

There may be good reasons for extending a third-party "final" class, which leads to more readable / supported code than completely duplicating it or creating some confusing work. And, of course, it’s preferable to change the source code of third-party developers and delete the “final” keyword.

PHP provides a “Component” extension to perform such a feat on those rare occasions when it is truly the best option. The following is an example showing how a child class can be defined as a "tag", which can then be used to dynamically extend the 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 ); ?> 
0
source share

I know this is an old post, but now I had a similar problem. I have included the same class file twice. Use include_once () or require_once () instead of include () or require ().

-3
source share

All Articles