ФорумПрограммированиеPHP для идиотовPHP и ООП → Првильно ли написан класс?

Првильно ли написан класс?

  • kart

    Сообщения: 52 Репутация: N Группа: Кто попало

    Spritz 28 июля 2007 г. 18:43

    Здравствуйте, товарисчи, короче такая штука… с ООП я знаком только в теории, всё времени не было изучить доскональнее, и вот, наконец, этот день настал! Принялся писать свой первый класс, но столкнулся с проблемой… Дело в том, что во всей просмотренной мною литературе основной акцент ставится на синтаксис, а вот о правильности реализации с точки зрения ООП сказано очень мало.

    Ниже приведён класс для генерации html таблиц, он полностью удовлетворяет мои нужды, но я не уверен, в правильности оформления… посмотрите его, пожалуйста, и прокомментируйте.

    Итак, мне достаточно часто приходится генерировать таблицы на лету, от самых простых, до относительно сложных (с различными css классами, js кодом и т.д.). Написанный класс сильно упрощает работу:


    // вытягиваю откуда-нить данные, и привожу их к следующему виду:
    $data[] = array('111', '222', '333');
    $data[] = array('111', '222', '333');
    $data[] = array('111', '222', '333');
    $data[] = array('111', '222', '333');

    // теперь вывожу самую простую таблицу
    $table = new CreateTable();
    $table->display($data);

    результат:


    <table>
    <tr>
    <td>111</td>
    <td>222</td>
    <td>333</td>
    </tr>

    </table>

    Но можно и усложнить, например:
    добавить заголовки (th) + css класс для каждого из них
    добавить классы любому столбцу (td)
    добавить поддержку чередования строк (tr), чтобы вставить js код или просто разукрасить таблицу

    короче ничего сложного, в результате html код должен выглядеть примерно так:
        <table id='myId' class='myClass'> 
    <tr>
    <th>Head1</th>
    <th class='center'>Head2</th>
    <th>Head3</th>
    </tr>
    <tr class='class_1'>
    <td>111</td>
    <td>222</td>
    <td class='right'>333</td>
    </tr>
    <tr class='class_2'>
    <td>111</td>
    <td>222</td>
    <td class='right'>333</td>
    </tr>
    <tr class='class_1'>
    <td>111</td>
    <td>222</td>
    <td class='right'>333</td>
    </tr>
    <tr class='class_2'>
    <td>111</td>
    <td>222</td>
    <td class='right'>333</td>
    </tr>
    </table>


    подобного можно добиться задействовав все возможные свойства и методы:
    $table = new CreateTable(); 
    $table->space = " "; // отступ от основного кода
    $table->SetTableId("myId"); // id таблицы
    $table->SetTableClass("myClass"); // класс таблицы
    $table->SetTrAttr("class='class_1'", "class='class_2'"); // чередование строк (любой js/css-код, который будет чередоваться)
    $table->SetThText("Head1", "Head2", "Head3"); // заголовки таблицы
    $table->SetThClass("", "center"); // имена классов для заголовков
    $table->SetTdClass("", "", "right"); // имена классов для столбцов
    $table->display($data); // вывод таблицы

    Все методы кроме display необязательны.
    А вот собственно и сам класс:

    class CreateTable {
    public $space;
    private $table_id;
    private $table_class;
    private $tr_attributes;
    private $th_text;
    private $th_class;
    private $td_class;

    public function display($content) {
    print $this->space."<table{$this->table_attributes()}> \r\n";
    if (is_array($this->th_text)) {
    print $this->space." <tr> \r\n";
    foreach ($this->th_text as $key => $th) {
    print $this->space." <th{$this->add_class("th", $key)}>{$th}</th> \r\n";
    }
    print $this->space." </tr> \r\n";
    }
    foreach ($content as $row) {
    print $this->space." <tr{$this->tr_attributes()}> \r\n";
    foreach ($row as $key => $td) {
    print $this->space." <td{$this->add_class("td", $key)}>{$td}</td> \r\n";
    }
    print $this->space." </tr> \r\n";
    }
    print $this->space."</table> \r\n";
    }

    public function SetTableId($id) {
    $this->table_id = $id;
    }

    public function SetTableClass($class) {
    $this->table_class = $class;
    }

    public function SetTrAttr() {
    $this->tr_attributes = func_get_args();
    }

    public function SetTdClass() {
    $this->td_class = func_get_args();
    }

    public function SetThText() {
    $this->th_text = func_get_args();
    }

    public function SetThClass() {
    $this->th_class = func_get_args();
    }

    private function table_attributes() {
    $attributes = "";
    if (!empty($this->table_id)) {
    $attributes .= " id='{$this->table_id}'";
    }
    if (!empty($this->table_class)) {
    $attributes .= " class='{$this->table_class}'";
    }
    return $attributes;
    }

    private function tr_attributes() {
    static $current;
    if (empty($current) || $current == count($this->tr_attributes)) {
    $current = 0;
    }
    if (!empty($this->tr_attributes[$current])) {
    return " " .$this->tr_attributes[$current++];
    }else {
    $current++;
    }
    }

    private function add_class($tag, $current) {
    if ($tag == "td") $foo = $this->td_class;
    elseif ($tag == "th") $foo = $this->th_class;
    if (isset($foo[$current])) {
    if (!empty($foo[$current])) {
    return " class='{$foo[$current]}'";
    }
    }
    }

    }


    Вопросы:
    1) правильно ли составлен класс, или можно было бы использовать возможности ооп более рационально?
    2) как лучше задавать значения свойствам (например id таблицы) - непосредственным присваиванием ($table->table_id = 'myId';) или с помощью методов как у меня?
    3) если я захочу нарисовать сразу несколько таблиц на странице, лучше каждый раз инициализировать класс, или можно обойтись только одной инициализацией, при этом очищать значения свойств после каждого вывода? (работает в обоих случаях, ведь ни конструкторов, ни диструкторов нет, но как правильнее?)

    что-то ещё хотел спросиль… ну лана, потом… чё-то и так дофига уже написал )))))
  • ghost

    Сообщения: 883 Репутация: N Группа: Джедаи

    Spritz 29 июля 2007 г. 7:18, спустя 12 часов 34 минуты 29 секунд

    вообще основной критерий правильного написания класса - удобство работы с этим классом
    можно было бы сделать базовый класс, а все навороты доделать наследованием. более мобильно, имхо
  • kart

    Сообщения: 52 Репутация: N Группа: Кто попало

    Spritz 29 июля 2007 г. 10:49, спустя 3 часа 31 минуту 26 секунд

    ghost, ты думаешь что мой класс следует разбить на подклассы? просто мне показалось, что он слишком примитивен для этого.
  • ghost

    Сообщения: 883 Репутация: N Группа: Джедаи

    Spritz 29 июля 2007 г. 11:34, спустя 44 минуты 53 секунды

    нет. твой класс реализует базовую функциональность. если потребуется какой-нибудь спец вывод его можно переопределить в потомках

    для этого нужно чтоб у базового класса функциональность была разбита на как можно более мелкие части.
    напр
    public function display($content) я вижу разбитым на 3 метода

    private function displayHeadTable($content) - выводит шапку таблицы
    private function displayBodyTable($content) - выводит боди таблицы
    private function displayBodyTableString($content) - выводит очередную строку таблицы

    и вообще говоря мне не удобно когда в классе есть echo или print.
    метод класса должен возвращать текстовое значение или ошибку, но не печатьт ее сразу (моё лично взятое мнение)
  • kart

    Сообщения: 52 Репутация: N Группа: Кто попало

    Spritz 29 июля 2007 г. 12:03, спустя 28 минут 38 секунд

    ghost, спасибо… не могу не согласиться.
    тока я чё-то недопонял насчет возврата значений. Как же тогда выводить данные?

    print $var->show($data); // ?

    или создать специальный метод для вывода?
  • ghost

    Сообщения: 883 Репутация: N Группа: Джедаи

    Spritz 29 июля 2007 г. 16:33, спустя 4 часа 30 минут 4 секунды

    меня вариант
    print $var->show($data);
    вполне устраивает

    класс возвращает хтмл-код, но это не догма, если удобно выводить по ходу - пусть выводит
  • Patrick

    Сообщения: 506 Репутация: N Группа: Кто попало

    Spritz 31 июля 2007 г. 16:19, спустя 1 день 23 часа 45 минут

    что разбивать класс надо то надо…
  • lеkafe

    Сообщения: 37 Репутация: N Группа: Кто попало

    Spritz 4 июля 2012 г. 12:40, спустя 1799 дней 20 часов 20 минут

    Я чебурашко!
  • SVat

    Сообщения: 23 Репутация: N Группа: Кто попало

    Spritz 4 июля 2012 г. 22:43, спустя 10 часов 3 минуты 53 секунды

    тока я чё-то недопонял насчет возврата значений. Как же тогда выводить данные?

    В методе класса делайте просто return и выводите так:
    echo $table->display($data);
  • arvitaly

    Сообщения: 292 Репутация: N Группа: Адекваты

    Spritz 6 июля 2012 г. 2:44, спустя 1 день 4 часа

    Отличный пример бессмысленного использования классов :-)
  • Nek

    Сообщения: 99 Репутация: N Группа: Адекваты

    Spritz 9 марта 2016 г. 16:15, спустя 1342 дня 14 часов 31 минуту

    @imbaq, взять и написать соотв. html, при необходимости сдабривая шаблонизатором (plain php тоже норм шаблонизатор кстати).
    Но вообще сия задача context dependent, то бишь надо смотреть на исходные требования.
    Нарисовать простейшую табличку можно в представлении, можно возвращать хтмл через метод (в некоторых простых случаях разумнее - через статический), можно запилить иерархию классов с композициями, миксинами, трейтами и т.п., если требуется что-то сложное.

    • согласен про базовый класс и разбитие на подклассы (только чтоб без переусложнения)
    • согласен про возврат значений вместо вывода в stdout в самих методах - современные фрейворки давно ползут в эту сторону, меньше зависисмости от деталей реализаций в наследниках, SOLID как бы и все такое
  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 9 марта 2016 г. 16:16, спустя 1 минуту 37 секунд

    (plain php тоже норм шаблонизатор кстати)

    @Nek, типичная ошибка. Plain php кусок говна.

    Сапожник без сапог
  • Nek

    Сообщения: 99 Репутация: N Группа: Адекваты

    Spritz 9 марта 2016 г. 16:19, спустя 2 минуты 20 секунд

    @phpdude, смотря как приготовить. Да и у любого шаблонизатора свои +/-

  • phpdude

    Сообщения: 26624 Репутация: N Группа: в ухо

    Spritz 9 марта 2016 г. 16:24, спустя 4 минуты 49 секунд

    @phpdude, смотря как приготовить. Да и у любого шаблонизатора свои +/-

    @Nek, как ни приготовь он гавно. Во первых он избыточен в силу синтаксиса языка, это всеж таки код будет и не надо забывать что это будет не код в шалоне, а шаблон в коде, поэтому это пизда. Ну и во вторых это годится отлько для хоумпейдж, ибо в любом покрупнее проекте пару сотен раз пропустишь htmlescape и отгребешь xss. Шаблонизатор должен по умолчанию абсолютно все эскейпить.

    Спустя 37 сек.

    А так да, на первый взгляд он выглядит как что-то легкое. Но это ошибочно, нельзя этому мнению доверять

    Сапожник без сапог
  • master

    Сообщения: 3236 Репутация: N Группа: Джедаи

    Spritz 9 марта 2016 г. 19:08, спустя 2 часа 44 минуты 21 секунду

    Шаблонизатор должен по умолчанию абсолютно все эскейпить.

    @phpdude, поэтому шаблонизатор должен компилировать шаблоны. если шаблонизатор шаблоны не комплириует - 99% что говно.

    не всё полезно, что в swap полезло

Пожалуйста, авторизуйтесь, чтобы написать комментарий!