Реализация класса HtmlList
Класс ListItem по сути этот тот же
класс Tag. С той разницей, что конструктор
класса Tag требует имя тега, а конструктор
ListItem не требует параметров, так
как всегда создает один и тот же
тег li.
Поэтому для реализации класса ListItem
достаточно просто просто наследовать от класса
Tag, переопределив его конструктор:
<?php
class ListItem extends Tag
{
public function __construct()
{
parent::__construct('li');
}
}
?>
Давайте теперь напишем реализацию класса
HtmlList. Данный класс также удобно
унаследовать от Tag, расширив затем
родителя нужными нам методами.
так, наследуем:
<?php
class HtmlList extends Tag
{
}
?>
Реализуем метод addItem для добавления
пунктов списка:
<?php
class HtmlList extends Tag
{
private $items = []; // массив для хранения лишек
public function addItem($li)
{
$this->items[] = $li;
return $this; // вернем $this для цепочки
}
}
?>
Давайте улучшим наш код, указав, что параметр
нашего метода принимает только объекты класса
ListItem:
<?php
class HtmlList extends Tag
{
private $items = [];
public function addItem(ListItem $li)
{
$this->items[] = $li;
return $this;
}
}
?>
Давайте теперь сделаем метод show.
На самом деле наш класс HtmlList наследует
от своего родителя такой метод - но этот
наследуемый метод делает немного не то, что
нам нужно.
Наследуемый метод show выводит открывающий
тег, закрывающий, а между ними текст. Но
в нашем случае в качестве текста будут выступать
теги li.
Давайте в таком случае просто переопределим
метод show родителя и напишем ему
свою реализацию:
<?php
class HtmlList extends Tag
{
private $items = [];
public function addItem(ListItem $li)
{
$this->items[] = $li;
return $this;
}
// Переопределим метод родителя:
public function show()
{
// тут будет наша реализация без вызова parent::show
}
}
?>
Пишем свою реализацию:
<?php
public function show()
{
$result = $this->open(); // открывающий тег
// тут надо сформировать лишки и добавить в $result
$result .= $this->close(); // закрывающий тег
return $result;
}
?>
Давайте сформируем лишки. Для этого запустим
цикл foreach для массива
$this->items:
<?php
public function show()
{
$result = $this->open();
foreach ($this->items as $item) {
$result .= 'тут нужно добавлять теги li';
}
$result .= $this->close();
return $result;
}
?>
В нашем цикле нужно в переменную $result
записывать теги li в формате:
<li>текст</li>
Здесь нам очень поможет то, что объекты класса
ListItem являются наследниками класса
Tag, а следовательно, имеют метод
show, который и делает то,
что нам нужно.
В нашем цикле foreach в переменную
$item как раз-таки попадают объекты
класса ListItem. Значит, просто будем
вызывать у них метод show и наша задача
будет решена:
<?php
public function show()
{
$result = $this->open();
foreach ($this->items as $item) {
$result .= $item->show(); // вызываем метод show
}
$result .= $this->close();
return $result;
}
?>
Добавим созданный метод show в наш
класс HtmlList:
<?php
class HtmlList extends Tag
{
private $items = [];
public function addItem(ListItem $li)
{
$this->items[] = $li;
return $this;
}
public function show()
{
$result = $this->open();
foreach ($this->items as $item) {
$result .= $item->show();
}
$result .= $this->close();
return $result;
}
}
?>
Давайте проверим работу нашего класса:
<?php
$list = new HtmlList('ul');
echo $list
->addItem((new ListItem())->setText('item1'))
->addItem((new ListItem())->setText('item2'))
->addItem((new ListItem())->setText('item3'))
->show();
?>
Результат выполнения кода выведет следующее (форматирование мое):
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
А теперь рассмотрим не очевидные на первый
взгляд бонусы: так как и класс HtmlList,
и класс ListItem наследуют от класса
Tag, то автоматически получают все
его методы, например, setAttr.
Это дает нам возможность задавать атрибуты создаваемых тегов. Смотрите пример:
<?php
$list = new HtmlList('ul');
echo $list->setAttr('class', 'eee')
->addItem((new ListItem())->setText('item1')->setAttr('class', 'first'))
->addItem((new ListItem())->setText('item2'))
->addItem((new ListItem())->setText('item3'))
->show();
/*
Результат выполнения кода выведет следующее:
<ul class="eee">
<li class="first">item1</li>
<li>item2</li>
<li>item3</li>
</ul>
*/
?>
Реализуйте самостоятельно описанные мною классы. Проверьте их работу.
Сделайте так, чтобы при преобразовании наших
классов к строке, метод show не нужно
было вызывать. Модифицируйте весь код в соответствии
с этим. Не забудьте про вот это место метода
show класса HtmlList:
<?php
foreach ($this->items as $item) {
$result .= $item->show(); // здесь тоже преобразование к строке
}
?>
Сделайте классы Ul и Ol, которые
будут наследовать от класса HtmlList.
Эти классы должны будут создавать соответствующий
тип списков. Пример:
<?php
$ul = new Ul; // сделаем список ul
$ol = new Ol; // сделаем список ol
?>
С помощью созданных классов выведите следующие списки:
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<ol>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ol>