通过PHP生成简单的HTML

时间:2018-02-20 11:57:27

标签: php html

我有一系列HTML标记:

class sampleHTML {
    public function __construct( $tag = [] ) {
        $html = [
            [
                'type' => 'p',
                'class' => '.sample-class',
                'content' => 'Sample content'
            ],
            [
                'type' => 'div',
                'class' => '.sample-class-2',
                'content' => 'Sample content 2'
            ],
        ];

        foreach( $html as $tag ) {
            new Tag( $tag );
        }
    }
}

我想从数组中生成HTML。到目前为止,我有以下类来生成HTML。

class Tag {

    public $tag;

    public function __construct( $tag = [] ) {
        $this->tag = $tag;

        switch ($tag['type']):
            case 'p':
                $this->render_p();
                break;
            case 'div':
                $this->render_div();
                break;
        endswitch;
    }

    private function render_p() {
        echo '<p class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</p>';
    }

    private function render_div() {
        echo '<div class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</div>';
    }

} 

没关系,但我想通过使用子类删除开关来改善我的代码。类似于以下内容:

class Tag {

    public $tag;

    public function __construct( $tag = [] ) {
        $this->tag = $tag;

        $this->render()
    }

    public function render() {};

}

class P extends Tag {
    public function render() {
        echo '<p class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</p>';
    }
}

class Div extends Tag {
    public function render() {
        echo '<div class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</div>';
    }
}

问题:

  1. 是否可以使用不带开关的子类?
  2. 如果是这样,如何根据标记类型动态调用子类的render方法。

3 个答案:

答案 0 :(得分:1)

您可以使用new $var()制作动态实例,然后移除您的开关。

foreach( $html as $tag ) {
   $class = ucfirst($tag['type']);
   $obj = new $class($tag); // will calls new P() or new Div()
   //$obj->render();
}  

完整代码:

class sampleHTML {
    public function __construct() {
        $html = [
            [
                'type' => 'p',
                'class' => '.sample-class',
                'content' => 'Sample content'
            ],
            [
                'type' => 'div',
                'class' => '.sample-class-2',
                'content' => 'Sample content 2'
            ],
        ];
        foreach( $html as $tag ) {
            $class = ucfirst($tag['type']);
            new $class( $tag );
        }
    }
}
class Tag {
    public $tag;
    public function __construct( $tag = [] ) {
        $this->tag = $tag;
        $this->render();
    }
    public function render() {}
}
class P extends Tag {
    public function render() {
        echo '<p class="' . $this->tag['class'] . '">' . $this->tag['content'] . '</p>';
    }
}
class Div extends Tag {
    public function render() {
        echo '<div class="' . $this->tag['class'] . '">' . $this->tag['content'] . '</div>';
    }
}
new sampleHTML();

输出:

<p class=".sample-class">Sample content</p><div class=".sample-class-2">Sample content 2</div>

答案 1 :(得分:1)

首先,我要说为每种标签类型创建类是一种开销(直到它只是一个学习的程序)。

基本上,您可以使用某种模式,例如FactoryStrategy

所以我会选择这样的东西:

interface TagInterface
{
    public function render();
}

class TagFactory
{
    public static function createTag($tag)
    {
        $class = ucfirst($tag['type']) . 'Tag';
        return new $class($tag);
    }
}

abstract class Tag implements TagInterface
{
    protected $tag;

    public function __construct(array $tag)
    {
        $this->tag = $tag;
    }
}

class PTag extends Tag
{
    public function render()
    {
        echo '<p class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</p>';
    }
}

class DivTag extends Tag
{
    public function render()
    {
        echo '<div class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</div>';
    }
}

然后在你的代码中:

foreach($html as $tag ) {
    /** @var TagInterface $tag */
    $tag = TagFactory::createTag($tag);
    $tag->render();
}

对于像您这样的任务,这是一个正确的架构。但是,我再说一遍,它只适合学习。在现实生活中,事情会简单得多,所以@Syscall的答案实际上应该是它的样子。

答案 2 :(得分:1)

  

是否可以在没有开关的情况下使用子类?

是的!你甚至可以在没有子类的情况下进行切换和 您已经将标记类型作为字符串,因此您可以使用它:

class Tag {

    public $tag;

    public function __construct( $tag = [] ) {
        $this->tag = $tag;

        $this->render();
    }

    private function render() {
        echo '<'.$this->tag['type'].' class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</'.$this->tag['type'].'>';
    }
} 

这样,就不需要像Div extends Tag这样的子类。

  

如何基于标签动态调用子类的render方法   类型?

虽然我的解决方案你不需要子类,但我也会回答这个问题 如果要从子类调用特定的渲染函数,请在该子类本身中定义/覆盖该函数

class Tag {
    // constructor

    // render 
    function render(){
        // standard tag html
        echo '<'.$this->tag['type'].' class"' . $this->tag['class'] . '">' . $this->tag['content'] . '</'.$this->tag['type'].'>';
    }
}

class Table extends Tag {
    // render (this overrides the render function of Tag)
    function render(){
        echo '<table class"' . $this->tag['class'] . '"><th><td>Column 1</td><td>Column 2</td><td>Column 3</td></th><tbody></tbody></table>';
    }
}

class Div extends Tag {
    // no render function here
    // this way Div uses the render function of Tag 
}

修改
如果您需要子类(因为某些标签以完全不同的方式构建)但您仍然拥有基本标签,例如p od div,您可以定义覆盖render() - 仅适用于那些的人一个不同的HTML。如果它是带有标准html的标记,则可以省略该子类中的render()函数,以便它将使用Tag类的render()函数。我编辑了上面的代码来代表这个想法。