【问题标题】:Extend Class with Final Constructor on PHP在 PHP 上使用最终构造函数扩展类
【发布时间】:2010-12-03 16:18:23
【问题描述】:

我想要扩展具有最终构造函数的类(在我的例子中是 SimpleXMLElement),但我遇到了问题,因为当我使用时:

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

我得到错误:

致命错误:无法覆盖 final 方法 SimpleXMLElement::__construct()

当我删除构造函数时,我得到这个错误:

致命错误:未捕获的异常 带有消息的“异常” 'SimpleXMLElement::__construct() 期望至少 1 个参数,给定 0'

我错过了一些东西或不明白如何正确调用最终的父构造函数。 我不想重写方法只是扩展类,但我不能扩展,因为它需要 __construct()。所以我错过了一些东西,然后又回到了开始的地方。

谁能解释我错在哪里?

【问题讨论】:

  • 看来这个类的编写方式使其难以扩展。可能是故意的。

标签: php


【解决方案1】:

我刚刚经历了这件事。你不需要扩展它。创建一个包含 SimpleXMLElement 对象的类。我相信这就是 Nikola 的意思。

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
    }
}

【讨论】:

    【解决方案2】:

    扩展第三方“最终”类可能有正当理由,与完全复制它或创建一些复杂的解决方法相比,这会产生更具可读性/可维护性的代码。并且肯定比更改第三方源代码和删除“final”关键字更可取。

    PHP 提供了扩展“Componere”来在极少数情况下完成这样的壮举,而 真正 是最好的选择。下面的示例展示了如何将子类定义为“特征”,然后可以将其用于动态扩展最终父类:

    <?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 );
    ?>
    

    【讨论】:

      【解决方案3】:

      在这种情况下,我会使用委托包装设计。您应该在这里考虑组合而不是继承。

      【讨论】:

        【解决方案4】:
        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 />");
           }
        }
        

        【讨论】:

          【解决方案5】:

          嗯,final 表示最终。没有覆盖该方法。即使你问得很好。我建议在你的新类中添加一个静态 make() 方法。比如:

          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;
              } 
          }
          

          【讨论】:

            【解决方案6】:

            我知道这是一篇旧帖子,但我刚才遇到了类似的问题。我实际上包含了两次相同的类文件。使用 include_once() 或 require_once() 代替 include() 或 require()。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-11-15
              • 2022-11-24
              • 2021-02-13
              • 2011-07-28
              • 2017-06-07
              • 1970-01-01
              • 1970-01-01
              • 2023-03-26
              相关资源
              最近更新 更多