在PHP上使用Final Constructor扩展类

时间:2010-12-03 16:18:23

标签: php

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

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

我收到错误:

  

致命错误:无法覆盖最终版   方法SimpleXMLElement :: __ construct()

当我删除构造函数时,我收到此错误:

  

致命错误:未捕获的异常   信息'异常'   “的SimpleXMLElement :: __构建体()   期望至少有一个参数,0给出'

我错过了一些或者不理解如何正确调用最终的父构造函数。 我不希望覆盖方法只是扩展类,但我无法扩展,因为它需要__construct()。所以我错过了一些东西,然后又开始了。

有人可以解释我错在哪里吗?

6 个答案:

答案 0 :(得分:3)

在这种情况下,我会使用Delegate包装器设计。你应该在这里考虑构成而不是继承。

答案 1 :(得分:3)

我刚刚完成了这件事。您不需要扩展它。创建一个包含SimpleXMLElement对象的类。我相信这就是尼古拉的意思。

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 :(得分:2)

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 />");
   }
}

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

答案 5 :(得分:-3)

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