Pers.narod.ru. PHP. Статьи. Пишем класс на PHP. Класс календаря на PHP |
В отношении классов PHP вполне оправдывает свою репутацию языка с низким порогом входимости. С одной стороны, это не позволит Вам сполна наслаждаться C++-подобными заумностями вроде "деструктор абстрактного класса должен быть всегда виртуальным", с другой стороны, классы на PHP просто удобны и хорошо решают свои задачи:
private
может, к тому же, защитить некоторые переменные и функции от изменения извне класса);
$i
из текущего скрипта с $myclass->i
из класса $myclass
.
По-моему, хороший класс должен хорошо описывать моделируемый объект, содержать достаточно понятных настроек и быть удобным в обращении, только и всего.
Возьмём для примера что-нибудь понятное и часто нужное, например, обычный григорианский календарь, и напишем для него класс.
Синтаксис класса на PHP может предельно упрощён. Все свойства и методы класса будут внутри его операторных скобок:
<?php class calendar { //... } ?>
Свойства (переменные) класса можно перечислить в начале, сразу же задавая им значения по умолчанию.
По сути, все эти переменные содержат те или иные настройки календаря, так что сделаем им тип
доступа public
, то есть, разрешим менять их значения извне. А вот значения текущих дня, месяца
и года менять извне не стоит, эти переменные будут иметь тип доступа private
(доступ только для функций
нашего класса). Есть ещё protected
, но он нужен только тогда, когда Вы собираетесь писать
классы-наследники, имеющие доступ к свойствам класса-родителя.
private $nday,$nmon,$nyear; //Текущие день, месяц и год - менять извне нельзя! public $dayslinecolor='#333333', //Цвет названия дней $holidaycolor='red', //Цвет выходных и названий выходных $weekdaycolor='#000066', //Цвет обычных дней $todaycolor='green', //Цвет сегодняшнего дня $maintabcolumns=4, //Сколько столбцов в таблице месяцев (1-12) $weekhorizontalorientation=false, //Горизонтальное положение недель (true-вкл.) $showform=false, //Показывать ли форму выбора года (true-вкл.) $year1=1970, //Год начала списка лет в форме $year2=2035, //Год окончания списка лет в форме $selectedyear, //Год, выбранный в форме как текущий $month1=1, //Первый месяц календаря $month2=12, //Последний месяц календаря $text = ''; //Будем код календаря писать в эту переменную, так легче потом интегрировать public $months=array("Январь","Февраль","Март","Апрель","Май","Июнь", "Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"); //Названия месяцев public $days=array("Пн","Вт","Ср","Чт","Пт","Сб","Вс"); //Названия дней недели public $dayscount=array("31","28","31","30","31","30", "31","31","30","31","30","31"); //Число дней в месяцах public $maincellspacing=5, //Расстояние между ячейками месяцев в главной таблице $maincellpadding=5, //Отступ от края ячейки месяца в главной таблице $monthsize=2, //Размер названий месяцев $months (1-7) $daysize=1; //Размер чисел в таблице месяца (1-7) public $links=array(); //Список ссылок для вывода в календаре public $defaultlinktarget='_self'; //Целевое окно ссылок календаря по умолчанию // '_self' - текущее окно, '_blank' - новое окно
Для создания конструктора на PHP нам достаточно включить в класс функцию со специальным именем
__construct
- она будет вызываться каждый раз, когда мы пишем в коде что-то вроде
$cal = new calendar();
В отличие от других языков программирования, у класса PHP может быть только один конструктор. В чём-то это даже удобно.
Явный конструктор классу на PHP имеет смысл задавать, когда мы собираемся выставить в нём значения приватных свойств или же значения общедоступных свойств, которые не являются константами.
Соответственно, в нашем классе это переменные $nday,$nmon,$nyear
и значение $selectedyear
, показывающее,
какой год выбран в форме лет (по умолчанию - текущий). Обратите внимание, как осуществляется
доступ к переменным (да и функциям) класса: $ИмяКласса->ИмяПеременной
, именно так, без символа "$
",
который обычно указывается в начале имени любой переменной, в том числе и переменной класса,
при её описании.
function __construct () { //Конструктор list($this->nyear,$this->nmon,$this->nday) = explode(".",date('Y.m.d')); $this->selectedyear=$this->nyear; }
Служебная функция leapyear ($y)
определит, является ли год $y високосным, а функция с заголовком
putform ($y1=1970,$y2=2035)
сформирует и вернёт строкой форму для выбора года
календаря с кнопкой "ОК".
Здесь после "=
" в заголовке функции указаны значения параметров по умолчанию,
так что putform (2011)
выдаст годы от 2011 до 2035, putform (2000,2040)
- от 2000 до 2040,
а просто putform ()
- от 1970 до 2035.
function leapyear ($y) { //true, если год високосный return ($y%4==0) and ($y%100!=0) or ($y%400==0); } function putform ($y1=1970,$y2=2035) { //Вывод формы выбора года $text=''; if (empty($_REQUEST['selectedyear'])) $this->selectedyear = $this->nyear; else $this->selectedyear = intval(strip_tags(trim($_REQUEST['selectedyear']))); $text.='<div align="center"><form action="'.$_SERVER['PHP_SELF']. '" method="POST"><select name="selectedyear" size="1">'; for ($year=$y1;$year<=$y2;$year++) { if ($this->selectedyear == $year) $sel = ' selected'; else $sel = ''; $text.="<option value=$year $sel>$year"; } $text.='</select> <input type="submit" value="OK"></center></form></div>'; return $text; }
Наконец, напишем функции, непосредственно формирующие календарь. Существуют два основных способа отобразить календарь на месяц - недели выводятся вертикально:
(примем это по умолчанию) или горизонтально:
Переключать способ вывода будет свойство класса $weekhorizontalorientation
.
Соответственно, нам понадобятся 2 функции с одинаковыми параметрами -
$firstday
- день недели первого дня месяца (0-6);
$mon
- номер месяца (1-12);
$year
- год;
$daysamount
- число дней в месяце.
Функции назовём drawverticalmonth
и drawhorizontalmonth
, обе они
будут просто возвращать строкой сформированный ими HTML-код календаря. Так же
поступит и фунцкия putcalendar($m1,$m2)
, которая сформирует календарь для указанного
диапазона месяцев
[$m1,$m2]
. Если задать только $m1
, получится календарь от текущего месяца до $m1
(при необходимости
они поменяются местами), если в параметрах не задать ничего - выведется календарь на
текущий месяц. В детали реализации вникать не будем, возможно, код неоптимален, так как
писался очень быстро.
function drawhorizontalmonth ($firstday,$mon,$year,$daysamount) { //Рисует горизонтальный календарь на месяц $text= "\n".'<table border="0" align="center"><caption><font size="'.$this->monthsize.'">'. $this->months[$mon-1].'</font></caption><tr>'; for ($i=0;$i<7;$i++) { $day=$this->days[$i]; $text.= '<td align="center"><font size="'.$this->daysize.'" color="'. ($i>4?$this->holidaycolor:$this->dayslinecolor).'">'.ucfirst($day).'</font></td>'; } $text.= '</tr><tr>'; for($i=0; $i<$firstday; $i++) $text.= '<td><font size="'.$this->daysize.'"> </font></td>'; for ($q=1; $q<$daysamount; $q++) { if ($q==$this->nday and $mon==$this->nmon and $year==$this->nyear) $color=$this->todaycolor; else if ($firstday<5) $color=$this->weekdaycolor; else $color=$this->holidaycolor; $firstday++; if ($firstday==7) $firstday=0; $text.= '<td align="right"><font size="'.$this->daysize.'" color="'.$color.'">'. $this->getdaylink($q,$mon,$year).'</font></td>'; if(!strstr(''.($i+$q)/7,'.')) $text.= '</tr><tr>'; } return $text.'</tr></table>'; } function drawverticalmonth ($firstday,$mon,$year,$daysamount) { //Рисует вертикальный календарь на месяц $wd1=$firstday+1; $pn1=($wd1==1? 1 : 0); $wd=$wd1; $cols=1; $maxDay=$daysamount-1; $m=$mon; for ($i=1; $i<=$maxDay; $i++) { $wd++; if ($wd>7) { if ($pn1==0) $pn1=$i+1; $wd=1; if ($i<$maxDay) $cols++; } } $text = "\n".'<table border="0" align="center"><caption><font size="'.$this->monthsize.'">'. $this->months[$mon-1].'</font></caption>'; for ($r=1; $r<8; $r++) { $wd=($pn1>1 ? $pn1+$r-1 : 7+$r ); $text.='<tr><td align="center"><font size="'.$this->daysize.'" color="'. ($r>5?$this->holidaycolor:$this->dayslinecolor).'">'.ucfirst($this->days[$r-1]).'</font></td>'; $rr=$r-($wd1-1); if ($rr==$this->nday and $m==$this->nmon and $year==$this->nyear) $color=$this->todaycolor; else if ($r>5) $color=$this->holidaycolor; else $color=$this->weekdaycolor; $text.='<td><font size="'.$this->daysize.'" color="'.$color.'">'. ($r<$wd1 ? ' ' : $this->getdaylink($rr,$mon,$year) ).'</font></td>'; for ($c=1; $c<$cols; $c++) { if ($wd==$this->nday and $m==$this->nmon and $year==$this->nyear) $color=$this->todaycolor; else if ($r>5) $color=$this->holidaycolor; else $color=$this->weekdaycolor; $text.='<td align="right"><font size="'.$this->daysize.'" color="'.$color.'">'. ($wd>$maxDay ? ' ' : $this->getdaylink($wd,$mon,$year)).'</font></td>'; $wd+=7; } $text.='</tr>'; } return $text.'</table>'; } function putcalendar ($m1=0,$m2=0) { //Возвращает календарь на месяцы [$m1,$m2] года $selectedyear if ($m1==0) $m1=$this->nmon; if ($m2==0) $m2=$this->nmon; if ($m1>$m2) { $a=$m1; $m1=$m2; $m2=$a; } $tabcol=$this->maintabcolumns; if ($m1==$m2) $tabcol=1; $text="\n".'<div align="center"><table border="0" cellspacing="'.$this->maincellspacing. '" cellpadding="'.$this->maincellpadding.'"><tr>'; $rows=0; $cols=0; for ($z=$m1;$z<=$m2;$z++) { $mon = $z; //Если форма не выводилась - selectedyear ставили в конструкторе $year = $this->selectedyear; $daysamount=($this->dayscount[$z-1])+1; if ($this->leapyear($year) and $z==2) $daysamount++; $firstday=date('w',mktime(0,0,0,$mon,0,(int)$year)); //0-6 if ($mon>$m1 and $cols%$tabcol==0) { $text.= '</tr><tr>'."\n"; $rows++; $cols=0; } $text.= '<td align="center" valign="top">'; $cols++; if ($this->weekhorizontalorientation) { //Рисуем месяц, когда недели по горизонтали $text.=$this->drawhorizontalmonth ($firstday,$mon,$year,$daysamount); } else { //Рисуем месяц, когда недели по вертикали $text.=$this->drawverticalmonth ($firstday,$mon,$year,$daysamount); } $text.= '</td>'; } if ($rows>0 and $cols<$tabcol) { //Дорисовать недостающие ячейки строки $voids = $tabcol - $cols; for ($i=0; $i<$voids; $i++) $text.='<td><font size="'.$this->daysize.'"> </font></td>'; } return $text.'</tr></table></div>'; }
Я не предполагаю здесь такой экзотики, как печать месяцев в календаре "по столбцам" или начало недели с воскресенья, как у американцев. При желании всё это, конечно, можно дописать, но это сделает код заметно более громоздким.
А вот сделать, чтобы номера дней можно было выводить с гиперссылками, было бы неплохо, например, это может понадобиться, если будем прикручивать календарь к какой-нибудь ленте новостей.
Здесь напрашиваются 2 метода -
addlink
будет ставить "ссылку дня", а
getdaylink
получать её. Конечно, можно предусмотреть ещё методы savelinks
и loadlinks
,
которые будут сохранять и читать
все ссылки из файла или базы данных, напишите их сами, если хочется.
function getdaylink ($day,$mon,$year,$target=0) { //Получить ранее сохранённую ссылку дня. $target может задавать имя окна (HTML). $t = mktime (0,0,0,$mon,$day,(int)$year); $tt=' target="'; if ($target) $tt.=$target; else $tt.=$this->defaultlinktarget; $tt.='"'; if (array_key_exists((int)$t,$this->links)) return '<a href="'.$this->links[$t].'"'.$tt.'>'.$day.'</a>'; else return ''.$day; } function addlink ($day,$mon,$year,$url) { //Сохранить ссылку $url для указанной даты $t = mktime (0,0,0,$mon,$day,(int)$year); $this->links[(int)$t] = $url; }
Наконец, метод show
просто покажет форму (при включённом свойстве $showform
) и календарь. При вызове
метода с параметром false
он будет возвращать строку календаря, но не выводить её.
function show ($show=true) { //Показать форму и календарь //Если нужно только вернуть всё строкой - вызвать метод с параметром false if ($this->showform) { $this->text.=$this->putform ($this->year1,$this->year2); } $this->text.=$this->putcalendar ($this->month1,$this->month2); if ($show) echo $this->text; return $this->text; }
Полную проверку корректности данных класс не делает, будем исходить из того, что использующий его понимает, что в году 12 месяцев :) Приведём пример использования класса:
<?php require_once ("calendar.php"); $cal = new calendar(); $cal->showform=true; list($nyear,$nmon,$nday) = explode(".",date('Y.m.d')); $cal->addlink (1,$nmon,$nyear,'http://www.ya.ru'); $cal->defaultlinktarget='_blank'; //$cal->maintabcolumns=1; $cal->show(); ?>
Здесь включается показ формы, добавляется ссылка на http://www.ya.ru
для первого дня текущего
месяца, целевым окном ссылок назначено новое окно.
Раскомментарьте строку
//$cal->maintabcolumns=1;
- и получите календарь в столбец, поставьте там значение 12 - в строку и т.д.
А вот так можно вызывать методы календаря "порознь" (при таком вызове выведется текущий месяц):
echo $cal->putform (); echo $cal->putcalendar ();
Этот пример в работе (прикручен файл form.php для выбора параметров)
Скачать код этого примера в архиве ZIP (могут быть мелкие изменения в коде) (5 Кб)
гостевая; E-mail |