渲染而不破坏封装

时间:2013-08-22 03:10:27

标签: php oop design-patterns rendering encapsulation

在不破坏封装的情况下实现此目的的正确方法是什么?我保持示例简单,但如果我决定添加更多实体,解决方案应该可以很好地扩展。我有一个学生和类似的课程:

class Student {

    private $id;
    private $name;

    /**
     * Courses student is attending
     * @var Course[]
     */
    private $courses = array();
    private $numberOfAttendingCourses;

}

class Course {

    private $code;

}

让我说我想渲染一下:

<ul>
    <li>[studentName] ([numberOfAttendingCourses])</li>
</ul>

这也是另一个用例中的视图

<ul>
    <li>[studentName] (ID: [studentId])
        <ul>
            <li>[course1Name] ([course1Code])</li>
            <li>[course2Name] ([course2Code])</li>
        </ul>
    </li>
</ul>

我知道如何使用getter和setter来实现它。我对保持两个对象尽可能封装的方式感兴趣。

1 个答案:

答案 0 :(得分:4)

最简单的方法是将值结构传递给模板渲染器。这将使您免于在模板本身内做太多逻辑。

例如 - 首先为您的可渲染类创建一个接口

class Renderable {
     public function getViewData();
}

然后让您的学生和课程类符合界面。

class Student implements Renderable{

    private $id;
    private $name;

    /**
     * Courses student is attending
     * @var Course[]
     */
    private $courses = array();
    private $numberOfAttendingCourses;
    public function getViewData(){
        $dat = array("id"=>$this->id, "name"=>$this->name, "courses"=>array());
        foreach($this->courses as $course){
            $dat["courses"][] = $course->getViewData();
        }
        $dat["numCourses"] = count($dat["courses"]);
        return $dat;
    }

}

class Course implements Renderable{

    private $code;
    private $name;

    public function fetchViewData(){
        return array("code"=>$this->code,
                     "name"=>$this->name);
    }
}

创建模板解析器。

class Template {
     public function render($templateFile, array $data){
          if ($data instanceof Renderable){
               $data = $data->getViewData();
          }
          extract ($data);
          ob_start();
          include($templateFile);
          ob_get_clean();
     }
}

然后是标记的简单模板

<ul>
    <li><?= htmlspecialchars($name) ?> (ID: <?= htmlspecialchars($id) ?>)
        <ul>
            <?php foreach($courses as $course): ?>
            <li><?= htmlspecialchars($course["code"]) ?> (<?= htmlspecialchars($course["code"]) ?>)</li>
            <?php endforeach; ?>
        </ul>
    </li>
</ul>

然后,一旦你有了一个有效的学生对象,你就可以

$template = new Template();
$template->render("/path/to/template.phtml", $student->fetchViewData());

这也使您可以非常简单地开发和测试模板,因为您可以使用可维护的数组,而不是去创建学生和一堆Course对象。