用其他XML源扩展SimpleXML类

时间:2020-08-17 17:57:06

标签: php simplexml

对于当前项目,能够扩展类SimpleXML以访问可遍历的SimpleXML的魔力将是很棒的。由于超出我的原因,构造函数是最终的。无论如何,我将如何扩展课程。

我所做的事情是避免在子类上使用构造函数,而是创建一个静态方法以返回XML字符串,该字符串可以在调用方中用于构造对象。不漂亮,因为它使调用者负担了应该隐藏的模式,但它可以正常工作。有没有更优雅的方法来规避拥有最终构造函数的阻碍性设计选择?

namespace acme.com;
class SubXML extends \SimpleXML{
   static public createXML() {
        // here we return a magnificent XML string
        // probably from a DB or a REST interface
   }
}

$o = new \SubXML( \SubXML::createXML() );

1 个答案:

答案 0 :(得分:1)

SimpleXMLElement上的构造函数不仅初始化一个PHP对象,而且调用一个外部库,该库初始化一些内部存储器结构,然后在遍历XML文档或片段时将其重用。

扩展类的一种受支持的方法是将类的名称作为第二个参数传递给simplexml_load_stringsimplexml_load_file,这将用于 all 的元素和属性遍历时例如:

class MyXML extends SimpleXMLElement {
    public function hello() { echo "Hello ", $this->getName(); }
}
$sx = simplexml_load_string('<foo><bar><baz>42</baz></bar></foo>', 'MyXML');
$sx->bar->baz->hello();

目前尚不清楚如果MyXML在这种情况下具有自定义构造函数会发生什么:应该为每个子元素调用它吗?有什么争论?


除此之外,您的实际需求似乎是要拥有某种工厂,该工厂从某个来源(数据库,API)获取数据并创建某种对象。您的静态方法似乎是明智的选择,但可以直接返回对象而不是字符串:

class SubXML extends SimpleXMLElement {
   public static function createXMLfromDB($db) {
        $xmlString = $db->query('Select XML from SpecialTable');
        return simplexml_load_string($xmlString, static::class);
   }
}

但是,我认为继承并不是表示这种情况的特别好方法-生成的对象可能不需要知道其数据来自何处,它需要能够表示该数据。因此,您的工厂可以是一个完全不同的类,以一种更加易于测试的方式来管理其依赖项:

class MyXMLFromDBFactory {
    private MyDBWrapper $db;

    public function __construct(MyDBWrapper $db) {
        $this->db = $db;
    }

    public function createXML() {
        $xmlString = $db->query('Select XML from SpecialTable');
        return simplexml_load_string($xmlString);
    }
}

然后,您可以有一个单独的MyXMLFromAPIFactoryMyXMLFromFileOnAmazonS3Factory等。如果需要,它们都可以返回 same 扩展的SimpleXMLElement类,或者甚至将类名作为参数,然后将其传递给simplexml_load_string