Сейчас мы с вами сделаем класс HtmlList
для создания списков ul
и ol
.
У этого класса будет метод addItem
для добавления пунктов списка и метод show
для вывода результата на экран.
Для самих пунктов списка также сделаем отдельный
класс, назовем его ListItem
. Вот пример
того, как мы будем пользоваться нашими классами:
<?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>
*/
?>
Реализация
Класс 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>