Здравствуйте. Помогите пожалуйста разобраться, как правильно работать с классами. Задача такая - создать объект Table и, манипулируя им, создать любую html табличку. То, что написал сейчас я, большей частью работает, но такое чувство, что подход не правильный. Кроме объекта "таблица" создаются объекты "строка" и "ячейка" и доступ к ним публичный. Т.е. можно написать new Tr и создастся строка, хотя, по идее, создавать строки должен уметь только класс Table, из вне это делать не к чему. Можно как-то заприватить один класс для всего, кроме другого класса? =) Или вообще не правильно подхожу к вопросу. Это было про подход, но есть еще и косяк... Вот это будет работать: Код (PHP): $table= new Table(2,2); $table->addAttr('border','1'); Это нет: Код (PHP): $table= new Table(2,2); $table->trArr[0]->addAttr('border','1'); Не могу врубиться, почему =( Вот класс: Код (PHP): <? interface TableTnterface{ public function __construct($trNum=0,$tdNum=0,$caption=''); public function writeCell($trNum,$tdNum,$content); public function addRow($num=1); public function addCol($num=1); public function addAttr($attr,$val); public function getHtml(); } abstract class Attributable{ public $attrArray; public function addAttr($attr,$val){ $this->attrArray[$attr]= $val; } public function getAttrStr(){ $attrStr= ''; foreach($this->attrArray as $name=>$value){ $attrStr.= ' '.$name.'="'.$value.'"'; } return $attrStr; } } class Td extends Attributable{ public $content; public function __construct($content='',$attrArray=array()){ $this->content= $content; $this->attrArray= $attrArray; } public function getHtml(){ return '<td'.$this->getAttrStr.'>'.$this->content.'</td>'; } } class Tr extends Attributable{ public $tdArr= array(); public function __construct($tdNum=0,$attrArray=array()){ for($i=0;$i<$tdNum;$i++){ $this->tdArr[]= new Td(); } $this->attrArray= $attrArray; } public function addTd($num=1){ for($i=0;$i<$num;$i++){ $this->tdArr[]= new Td(); } } public function getHtml(){ $tdsStr= ''; foreach($this->tdArr as $td){ $tdsStr.= $td->getHtml(); } return '<tr'.$this->getAttrStr.'>'.$tdsStr.'</tr>'; } } class Table extends Attributable implements TableTnterface{ public $caption; private $trNum; private $tdNum; public $trArr= array(); public function __construct($trNum=0,$tdNum=0,$caption=''){ for($i=0;$i<$trNum;$i++){ $this->trArr[]= new Tr($tdNum); } $this->caption= $caption; $this->trNum= $trNum; $this->tdNum= $tdNum; } public function addRow($num=1){ for($i=0;$i<$num;$i++){ $this->trArr[]= new Tr($this->tdNum); } $this->trNum+= $num; } public function addCol($num=1){ for($i=0;$i<$this->trNum;$i++){ //для всех строк $this->trArr[$i]->addTd($num); } $this->tdNum+= $num; } public function writeCell($trNum,$tdNum,$content){ if($trNum>$this->trNum){ //если строки нет $this->addRow($trNum-$this->trNum); } if($tdNum>$this->tdNum){ //если столбца нет $this->addCol($tdNum-$this->tdNum); } $this->trArr[$trNum-1]->tdArr[$tdNum-1]->content= $content; } public function getHtml(){ $caption= ''; if($this->caption) $caption= '<caption>'.$this->caption.'</caption>' ; $trsStr= ''; foreach($this->trArr as $tr){ $trsStr.= $tr->getHtml(); } return '<table'.$this->getAttrStr().'>'.$caption.'<tbody>'.$trsStr.'</tbody></table>'; } } PHP, JavaScript, SQL и другой код пишите внутри тегов Код ( (Unknown Language)): [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
видимо, свойство Код (Text): $table->trArr[0] не обладает методом Код (Text): addAttr ну, а что бы врубиться, нужно чуток почитать про ОПП и поковырять
обладает... это свойство является массивом из объектов Tr. Эти объекты наследуют метод через extends Attributable. Так же, как и объекты Table. Но с объектами Table все работает, а с Tr нет. Хотя оба extends Attributable. Добавлено спустя 9 минут 52 секунды: при попытке $table->trArr[0]->addAttr('border','1'); выдает ошибку в сроке 17: Код (PHP): abstract class Attributable{ public $attrArray; public function addAttr($attr,$val){ $this->attrArray[$attr]= $val; } public function getAttrStr(){ $attrStr= ''; foreach($this->attrArray as $name=>$value){ //это строка 17 $attrStr.= ' '.$name.'="'.$value.'"'; } return $attrStr; } } т.е. плохой аргумент для foreach. В объектах Table он не плохой, а в Tr почему-то плохой =) PHP, JavaScript, SQL и другой код пишите внутри тегов Код ( (Unknown Language)): [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
Туда вообще пустая переменная приходит. Хотя, по идее, я ее задаю так: $table->trArr[0]->addAttr('border','1'); Как я понимаю, что должно происходить: Берется первый объект Tr из trArr свойства-массива объекта Table. Т.е. первая строка таблицы. Этот объект Tr наследует свойство $attrArray и метод addAttr($attr,$val) из абстрактного класса Attributable (также, как это делают объекты Table и с ними все работает!). Этот метод запишет в свойство $attrArray наши border и 1. Но когда я прошу этот же объект сделать метод getAttrStr(), свойство $attrArray уже пустое и выдает ошибку Invalid argument supplied for foreach(). Не понимаю в чем подвох =( Добавлено спустя 2 минуты 8 секунд: NULL
так всё так и, может, всё иначе, а не так как ты понимаешь ? ))) что бы понять, почитай лучшее по ОПП и делай Код (Text): var_dump($this->???); в методах
Извиняюсь! не правильно описал ошибку в первом сообщении. Понял только сейчас. Код (Text): $table= new Table(2,2); $table->trArr[0]->addAttr('border','1'); это ошибку не выдаст. вылетит она когда после этого попытаюсь показать таблицу: Код (Text): $table= new Table(2,2); $table->trArr[0]->addAttr('border','1'); echo $table->getHtml();
а как же Код (Text): Notice: Undefined property: Td::$getAttrStr in ... on line Notice: Undefined property: Td::$getAttrStr in ... on line Notice: Undefined property: Tr::$getAttrStr in ... on line Notice: Undefined property: Td::$getAttrStr in ... on line Notice: Undefined property: Td::$getAttrStr in ... on line Notice: Undefined property: Tr::$getAttrStr in ... on line ???
похоже, эти ошибки у меня выключены. надо включить, спасибо. исправил в декларации public $attrArray= array(); добавил значением по умолчанию пустой массив. думаю, должны пропасть Добавлено спустя 3 минуты 39 секунд: теперь ошибки нет, в var_dump($this->attrArray); приходит пустой массив. проблема только, что он пустой)
все, нашел косяк. обращался к методу как к свойству, забыл про скобки =( return '<tr'.$this->getAttrStr.'>'.$tdsStr.'</tr>'; return '<tr'.$this->getAttrStr().'>'.$tdsStr.'</tr>'; остался вопрос о правильности подхода, нужно ли как-то скрывать доступ к объектам строка и ячейка... ну да ладно, главное все правильно работает
выложу на всякий случай итоговый рабочий код. если вдруг кто-то попадет сюда через поиск и эта ересь куму-то понадобится =) Класс умеет создавать таблицы заданной высоты/ширины. Также можно создать пустую, она будет автоматически расширяться по мере обращения к несуществующим элементам. если добавляется уже существующий атрибут, то его значение дописывается к старому через пробел Код (PHP): <? interface TableTnterface{ public function __construct($trNum=0,$tdNum=0,$caption=''); public function writeCell($trNum,$tdNum,$content); public function addRow($num=1); public function addCol($num=1); public function addAttr($attr,$val); public function addAttrToRow($numRow,$attrName,$attrValue); public function addAttrToRowCells($numRow,$attrName,$attrValue); public function addAttrToColCells($numCol,$attrName,$attrValue); public function addAttrToCell($numRow,$numCol,$attrName,$attrValue); public function getHtml(); } abstract class Attributable{ public $attrArray= array(); public function addAttr($attr,$val){ if(isset($this->attrArray[$attr])){ $this->attrArray[$attr].= ' '.$val; }else{ $this->attrArray[$attr]= $val; } } public function getAttrStr(){ $attrStr= ''; foreach($this->attrArray as $name=>$value){ $attrStr.= ' '.$name.'="'.$value.'"'; } return $attrStr; } } class Td extends Attributable{ public $content; public function __construct($content=''){ $this->content= $content; } public function getHtml(){ return '<td'.$this->getAttrStr().'>'.$this->content.'</td>'; } } class Tr extends Attributable{ public $tdArr; public function __construct($tdNum=0){ for($i=0;$i<$tdNum;$i++){ $this->tdArr[]= new Td(); } } public function addTd($num=1){ for($i=0;$i<$num;$i++){ $this->tdArr[]= new Td(); } } public function getHtml(){ $tdsStr= ''; foreach($this->tdArr as $td){ $tdsStr.= $td->getHtml(); } return '<tr'.$this->getAttrStr().'>'.$tdsStr.'</tr>'; } } class Table extends Attributable implements TableTnterface{ public $caption; private $_trNum; private $_tdNum; private $trArr= array(); public function __construct($trNum=0,$tdNum=0,$caption=''){ for($i=0;$i<$trNum;$i++){ $this->trArr[]= new Tr($tdNum); } $this->caption= $caption; $this->_trNum= $trNum; $this->_tdNum= $tdNum; } private function trNumControl($num){ if($num>$this->_trNum){ //если строки нет $this->addRow($num-$this->_trNum); if($this->_tdNum===0){ $this->addCol(); } } } private function tdNumControl($num){ if($num>$this->_tdNum){ //если столбца нет if($this->_trNum===0){ $this->addRow(); } $this->addCol($num-$this->_tdNum); } } public function addRow($num=1){ for($i=0;$i<$num;$i++){ $this->trArr[]= new Tr($this->_tdNum); } $this->_trNum+= $num; } public function addCol($num=1){ for($i=0;$i<$this->_trNum;$i++){ //для всех строк $this->trArr[$i]->addTd($num); } $this->_tdNum+= $num; } public function addAttrToRow($numRow,$attrName,$attrValue){ $this->trNumControl($numRow); $this->trArr[$numRow-1]->addAttr($attrName,$attrValue); } public function addAttrToRowCells($numRow,$attrName,$attrValue){ $this->trNumControl($numRow); foreach($this->trArr[$numRow-1]->tdArr as $td){ $td->addAttr($attrName,$attrValue); } } public function addAttrToColCells($numCol,$attrName,$attrValue){ $this->tdNumControl($numCol); foreach($this->trArr as $tr){ $tr->tdArr[$numCol-1]->addAttr($attrName,$attrValue); } } public function addAttrToCell($numRow,$numCol,$attrName,$attrValue){ $this->trNumControl($numRow); $this->tdNumControl($numCol); $this->trArr[$numRow-1]->tdArr[$numCol-1]->addAttr($attrName,$attrValue); } public function writeCell($trNum,$tdNum,$content){ $this->trNumControl($trNum); $this->tdNumControl($tdNum); $this->trArr[$trNum-1]->tdArr[$tdNum-1]->content= $content; } public function getHtml(){ $caption= ''; if($this->caption) $caption= '<caption>'.$this->caption.'</caption>' ; $trsStr= ''; foreach($this->trArr as $tr){ $trsStr.= $tr->getHtml(); } return '<table'.$this->getAttrStr().'>'.$caption.'<tbody>'.$trsStr.'</tbody></table>'; } } Пример использования: Код (PHP): $table= new Table(); $table->writeCell(1,1,'1'); $table->writeCell(1,2,'2'); $table->writeCell(1,3,'3'); $table->writeCell(2,2,'4'); $table->writeCell(3,3,'5'); $table->writeCell(4,1,'6'); $table->addAttr('border','1'); $table->addAttr('class','a'); $table->addAttrToColCells(1,'style','background-color:#bbb;'); $table->addAttrToRowCells(1,'style','background-color:#888;'); $table->addAttrToCell(4,3,'style','background-color:#f88;'); echo $table->getHtml(); PHP, JavaScript, SQL и другой код пишите внутри тегов Код ( (Unknown Language)): [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
Это лучше как трейт оформить (если php >= 5.4). А вообще, интересная идея. Мне не разу не приходило в голову делать класс для вёрстки
странно, я этот класс переписал, наверно старую версию отправил в сообщении выше. сейчас он дописывает новые значения атрибутов через пробел. Код (PHP): abstract class Attributable{ public $attrArray= array(); public function addAttr($attr,$val){ if(isset($this->attrArray[$attr])){ $this->attrArray[$attr].= ' '.$val; }else{ $this->attrArray[$attr]= $val; } } public function getAttrStr(){ $attrStr= ''; foreach($this->attrArray as $name=>$value){ $attrStr.= ' '.$name.'="'.$value.'"'; } return $attrStr; } } исправил прошлое сообщение. спасибо, посмотрю что это такое)
тогда да, сейчас нет, ибо этот массив я заприватил =) дописал методы, которые с ним работают, и заприватил. мало ли в голову взбредет удалить из него что-то, а счетчики высоты-ширины таблицы тикают только в методах