用其他 XML 来源扩展 SimpleXML class
extend the SimpleXML class with other XML sources
对于当前的项目,如果能够扩展 class SimpleXML 以访问 SimpleXML 可遍历的魔力,那就太好了。出于某种超出我的原因,构造函数是最终的。无论如何,我将如何扩展 class。
到目前为止我所做的是避免在子class上使用构造函数,而是为return创建一个静态方法,一个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() );
SimpleXMLElement 上的构造函数不只是初始化一个 PHP 对象,而是调用一个外部库来初始化一些内部内存结构,然后在您遍历 XML 文档或片段。
一种支持扩展 class 的方法是将 class 的名称作为第二个参数传递给 simplexml_load_string or simplexml_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)获取数据并创建某种对象。您的静态方法似乎是一个明智的方向,但可以 return 直接对象而不是字符串:
class SubXML extends SimpleXMLElement {
public static function createXMLfromDB($db) {
$xmlString = $db->query('Select XML from SpecialTable');
return simplexml_load_string($xmlString, static::class);
}
}
但是,我认为继承并不是首先表示这一点的特别好的方式 - 结果对象可能不需要知道它的数据来自哪里,它需要能够表示数据。因此,您的工厂可以是一个完全不同的 class,以更 test-friendly 的方式管理其依赖关系:
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);
}
}
那你可以有一个单独的MyXMLFromAPIFactory
,MyXMLFromFileOnAmazonS3Factory
,等等,如果你愿意,这些都可以return和一样扩展 SimpleXMLElement
class,甚至将 class 名称作为参数并将其传递给 simplexml_load_string
.
对于当前的项目,如果能够扩展 class SimpleXML 以访问 SimpleXML 可遍历的魔力,那就太好了。出于某种超出我的原因,构造函数是最终的。无论如何,我将如何扩展 class。
到目前为止我所做的是避免在子class上使用构造函数,而是为return创建一个静态方法,一个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() );
SimpleXMLElement 上的构造函数不只是初始化一个 PHP 对象,而是调用一个外部库来初始化一些内部内存结构,然后在您遍历 XML 文档或片段。
一种支持扩展 class 的方法是将 class 的名称作为第二个参数传递给 simplexml_load_string or simplexml_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)获取数据并创建某种对象。您的静态方法似乎是一个明智的方向,但可以 return 直接对象而不是字符串:
class SubXML extends SimpleXMLElement {
public static function createXMLfromDB($db) {
$xmlString = $db->query('Select XML from SpecialTable');
return simplexml_load_string($xmlString, static::class);
}
}
但是,我认为继承并不是首先表示这一点的特别好的方式 - 结果对象可能不需要知道它的数据来自哪里,它需要能够表示数据。因此,您的工厂可以是一个完全不同的 class,以更 test-friendly 的方式管理其依赖关系:
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);
}
}
那你可以有一个单独的MyXMLFromAPIFactory
,MyXMLFromFileOnAmazonS3Factory
,等等,如果你愿意,这些都可以return和一样扩展 SimpleXMLElement
class,甚至将 class 名称作为参数并将其传递给 simplexml_load_string
.