1

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

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 来实现这一点。我对尽可能地封装两个对象的方式很感兴趣。

4

1 回答 1

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());

这也应该使您开发和测试模板变得非常简单,因为您将能够使用可服务的数组,而不是去创建一个学生和一堆课程对象。

于 2013-08-26T20:19:43.123 回答