Extend Class with Final Constructor on PHP

后端 未结 6 968
栀梦
栀梦 2021-01-06 02:43

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         


        
相关标签:
6条回答
  • 2021-01-06 03:04

    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 );
    ?>
    
    0 讨论(0)
  • 2021-01-06 03:07

    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;
        } 
    }
    
    0 讨论(0)
  • 2021-01-06 03:13

    I would use Delegate wrapper design in this case. You should consider composition instead of inheritance here.

    0 讨论(0)
  • 2021-01-06 03:19

    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
        }
    }
    
    0 讨论(0)
  • 2021-01-06 03:19

    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().

    0 讨论(0)
  • 2021-01-06 03:30
    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 />");
       }
    }
    
    0 讨论(0)
提交回复
热议问题