扩展或实现simplexml以避免DRY

时间:2017-11-17 17:06:14

标签: php xml php-7

请检查我创建的以下类,以构建少量XML框架。

class CommandBuilder
{
    public function __construct()
    {
        //
    }

    public function login($username, $password)
    {
        $frame = $this->frame();

        $command = $frame->addChild('command');
        $login = $command->addChild('login');
        $login->addChild('username', $username);
        $login->addChild('password', $password);
        $command->addChild('authKey', 'authkey');

        return $frame->asXML();
    }

    public function info($id)
    {
        $frame = $this->frame();

        $command = $frame->addChild('command');
        $login = $command->addChild('product');
        $login->addChild('id', $id);
        $command->addChild('authKey', 'authkey');

        return $frame->asXML();
    }

    protected function frame()
    {
        return new SimpleXMLElement(
            '<app/>'
        );
    }
}

避免重复$frame->addChild('command')$command->addChild('authKey', 'authkey')而不改变元素顺序的最佳方法是什么?

请帮助改进代码。感谢

3 个答案:

答案 0 :(得分:0)

虽然你的代码可以简化,但也有并发症。我完成它的方式将框架的构建移动到frame方法。每个其他例程构建<command>节点的基础并将其传递,然后帧方法添加authkey位。这段代码也会这样做 - 但它必须在所有帧上完成......

class CommandBuilder
{
    public function __construct()
    {
        //
    }

    public function login($username, $password)
    {
        $command = new SimpleXMLElement('<command />');
        $login = $command->addChild('login');
        $login->addChild('username', $username);
        $login->addChild('password', $password);

        return $this->frame($command);
    }

    public function info($id)
    {
        $command = new SimpleXMLElement('<command />');
        $login = $command->addChild('product');
        $login->addChild('id', $id);

        return $this->frame($command);
    }

    protected function frame( $node )   {
        $node->addChild('authKey', 'authkey');
        $xml = new DOMDocument();
        $xml->loadXML('<app/>');
        // Convert SimpleXML to DOMDocument
        $fromDom = dom_import_simplexml($node);
        // Add in the $node passed in to the frame
        $xml->documentElement->appendChild($xml->importNode($fromDom, true));

        return $xml->saveXML();
    }
}

答案 1 :(得分:0)

看起来你的依赖关系不是太混乱所以这是一个相当简单的例子,你可以将它移动到它自己的方法中。请记住,在PHP中,对象通过引用传递。这意味着对象变量实际上只是一个指向对象的内存指针,与默认情况下标量和数组变量的传递方式形成对比(通过值...也就是没有内存指针)。

需要注意的是,只要你没有clone,对象就会一直使用它。

<?php
class CommandBuilder
{
    public function preBuild(\SimpleXMLElement $node)
    {
        $command = $node->addChild('command');
        $command->addChild('authKey', 'authkey');
    }
}

现在,您只需拨打$this->preBuild($frame)

,而不是调用这两种方法

答案 2 :(得分:0)

如何编写一个“骨架”方法,接受一个可调用的参数,并在中间执行它,就像这样。 (缺点是现在,重复参数,如$username$password。)

class CommandBuilder
{
    // ...

    private function createCommand(callable $cmdEnricher)
    {
        $frame = $this->frame();

        $command = $frame->addChild('command');
        $cmdEnricher($command);
        $command->addChild('authKey', 'authkey');

        return $frame->asXML();
    }

    public function login($username, $password)
    {
        return $this->createCommand(function ($command) use ($username, $password) {
            $login = $command->addChild('login');
            $login->addChild('username', $username);
            $login->addChild('password', $password);
        });
    }

    public function info($id)
    {
        return $this->createCommand(function ($command) use ($id) {
            $login = $command->addChild('product');
            $login->addChild('id', $id);
        });
    }

    // ...
}