# Реализация класса 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>`
← →
↑