[ главная ]   [ рейтинг статей ]   [ справочник радиолюбителя ]   [ новости мира ИТ ]



Ответов: 0
25-02-12 07:01







   Web - программирование
PHP


ASP






XML



CSS

SSI





   Программирование под ОС











   Web - технологии








   Базы Данных









   Графика






Данные




Web - программирование / PHP /

Шаблонизатор на PHP своими руками

Автор: elrevin

Эта статья предназначена для тех кто не относится скептически к написанию того что уже написано, в общем она для энтузиастов, каким я сам и являюсь.

Начнем с того, что определим что будет уметь наш шаблонизатор:

  • выделение из шаблона на блоков
  • обработка блоков
  • подстановка переменных

Блоки.

Блоки могут быть "циклические" и "не циклические". К первым отнесем блоки приразборе которых шаблонизатор выполнит цикл с определенными параметрами и вставит "внутренности" блока в результирующую страницу несколько раз. Они нам понадобятся массовой для публикации данных (например список заголовков новостей). Ко вторым отнесем условные конструкции (зачастую без них не обойтись).

Имена блоков будем хранить в массиве:

 
$Blocks=array (array('открывающий тег',
                     'закрывающий тег',признак цикличного блока));

Чтобы было понятнее разберем пример.

есть таблица новостей:

 
create table news 
(
	id int(10) unsigned NOT NULL auto_increment,
	title varchar(128),
	body text,
	ndate date,
	primary key (id)
);

нужно создать шаблон для вывода этих новостей и php скрипт обрабатывающий этот шаблон.

Договоримся - теги блоков и переменных будем заключать в HTML комментарии:

 
<!--news-->
	содержимое блока
<!--end_news-->

теперь функция выделения блока или переменной:

 
function ParseTmpl($Block)
{
  global $Blocks;
  global $Vars;
  // Ищем блоки
  $Pos=0;
  while (($Pos=strpos($Block,'<!--',$Pos))!==false)
  {
    $BlockId=GetIsBlock($Block,$Pos);
    if ($BlockId!=-1)
    {
      // ищем закрывающий тег блока
      $BlockEnd='<!--'.($Blocks[$BlockId][1]).'-->';
      if ($EndIndex=strpos($Block,$BlockEnd,$Pos))
      {
        $EndIndex+=strlen($BlockEnd);

        $SubBlock=substr($Block,$Pos,$EndIndex-$Pos);
        $Block=substr($Block,0,$Pos).
               Block($SubBlock,$BlockId).
               substr($Block,$EndIndex);
      }
    }
    else
    {
      $Pos=strpos($Block,'-->',$Pos);
    }
  }

  //Выделяем переменные

  for ($i=0; $i<count($Vars); $i++)
  {
    $Begin=$Vars[$i];
    while ($Pos=strpos($Block,'<!--'.$Begin))
    {
      $BeginIndex=$Pos;
       if ($EndIndex=strpos($Block,'-->',$BeginIndex))
       {
        $Sub=substr($Block,$BeginIndex,$EndIndex-$BeginIndex+3);
        $Block=substr($Block,0,$BeginIndex).
               Variable($Sub,$i).substr($Block,$EndIndex+3);
       }
    }
  }
  return $Block;
}

В качестве аргумента ей передается шаблон или его фрагмент (почему фрагмент? Потому что в нутри блока может быть еще один блок, то есть "внутренность" блока необходимо обработать отдельно). Далее она ищет вхождения строки <!--, если находит, то проверяет не является ли найденная строка тегом шаблонизатора, для этого напишем еще одну функцию - GetIsBlock($Block,$Offset), которой передаются тот же фрагмент шаблона и смещение в нутри его, то есть позицию найденного вхождения стоки <!--, возвращает она индекс имени блока из массива $Blocks или -1 если найденная строка не является тегом шаблонизатора.Код этой функции можно увидеть немного ниже. продолжаем разбирать шаблон. Если после проверки выясняется, что найденная строка - тег шаблонизатора, и является блочным, ищем его закрывающий тег. Выделяем подблок, то есть сами теги блока и внутренности, и передаем все это функции Block($Block, $BlockId), которая обрабатывает блок.

Теперь обещанная функция GetIsBlock($Block,$Offset), она простая поэтому думаю комментировать нет необходимости:

 
function GetIsBlock($Block,$Offset)
{
  global $Blocks;
   // Выделяем имя блока
  $EndInd=strpos($Block,'-->',$Offset);
  if (($Offset+4)!=$EndInd)
  {
    $S=substr($Block,$Offset+4,$EndInd-($Offset+4));
    $Bl=explode(' ',$S);
    $BlockName=$Bl[0];
    for ($i=0; $i<count($Blocks); $i++)
    {
      if ($Blocks[$i][0]==$BlockName)
      {
      	return $i;
      }
    }
	}

	return -1;
}

Рассмотри работу функции Block($Block, $BlockId):

 
function Block($Block, $BlockId)
{
  global $Blocks;
  $Ret='';
	// Получаем параметры
	$BeginStr=$Blocks[$BlockId][0];
	$BeginLength=4+strlen($BeginStr);
	$EndOperatorPos=strpos($Block,'-->');
	$Operator=substr($Block,$BeginLength,$EndOperatorPos-$BeginLength);
	$Args=explode(' ',trim($Operator));

	$EndBlockPos=strpos($Block,'<!--'.$Blocks[$BlockId][1].'-->');
	$SubBlock=substr($Block,$EndOperatorPos+3,$EndBlockPos-$EndOperatorPos-3);
	if ($Blocks[$BlockId][2]) // блок не цикличный
	{
  	if ($BeginStr($Args))
  	{
      $Ret.=ParseTmpl($SubBlock);
  	}
	}
	else
	{
  	while ($BeginStr($Args))
  	{
      $Ret.=ParseTmpl($SubBlock);
  	}
  }
  return $Ret;
}

Ей передаются фрагмент шаблона, содержащий рассматриваемый блок, и индекс блока в массиве $Blocks. Для начала в ней мы разбираем строку открывающего тега, на предмет параметров (это на всякий случай, а вдруг Вам необходимо вывести не все новости а какое-то количество). То есть если блок новостей начинается со строки:

 
<!--news 5-->

Где 5 - количество выводимых новостей.

Мы должны иметь возможность выделить именно определенное количество новостей. Далее выделяется "внутренность" блока в переменню $SubBlock, для дальнейшего парсирования. Далее в зависимости от результатов проверки на цикличность блока вызываем уже знакомую нам функцию ParseTmpl, либо при выполнении условия, либо в цикле до не выполнения условия. Условием является не нулевой результат выполнения функции одноименной с блоком.

Для каждого циклического блока необходимо создать функцию которая бы возвращала 0 или не 0 в зависимости от того нужно ли повторять разбор блока. Это может быть функция которая будет при каждом вызове выбирать очередную порцию данных из таблицы новостей и возвращать 1 если например количество выбранных новостей не больше количества вереданного ей в качестве одного из элементов массива аргументов блока.

Переменные.

Переменные будем хранить в массиве

$Vars=array('имя переменной');

Так же как и в случае с блоками создадим одноименные функции которые бы возвращали значения этих переменных (брали их, например, из базы данных). Вот участок функции ParseTmpl выделяющий переменные из шаблона и подставляющий их значения:

 
  for ($i=0; $i<count($Vars); $i++)
  {
    $Begin=$Vars[$i];
    while ($Pos=strpos($Block,'<!--'.$Begin))
    {
      $BeginIndex=$Pos;
       if ($EndIndex=strpos($Block,'-->',$BeginIndex))
       {
        $Sub=substr($Block,$BeginIndex,$EndIndex-$BeginIndex+3);
        $Block=substr($Block,0,$BeginIndex).
               Variable($Sub,$i).substr($Block,$EndIndex+3);
       }
    }
  }

И функция Variable:

function Variable($Block, $VarId)
{
  global $Vars;
  $Ret='';
	// Получаем параметры
	$BeginStr=$Vars[$VarId];
	$BeginLength=4+strlen($BeginStr);
	$EndOperatorPos=strpos($Block,'-->');
	$Operator=substr($Block,$BeginLength,$EndOperatorPos-$BeginLength);
	$Args=explode(' ',trim($Operator));
  return $BeginStr($Args);
}

Она похожа на функцию Block, но значительно проще.

Пример шаблона и функции блоков и переменных.

Шаблон вывода наших новостей:

 
<table>
	<!--news 5-->
		<tr>
			<td>
				[<b><!--ndate--></b>] <!--ntitle-->
			</td>
		</tr>
		<tr>
			<td>
				<!--nbody-->
			</td>
		</tr>
	<!--end_news-->
</table>

А вот код для работы с блоками и переменными:

 
$QueryResult_News=0;
$QueryRow_News=0;

function news($Args) // Блок news
{
  global $QueryResult_News;
  global $QueryRow_News;

  $Active=$Args[0];
  if ($QueryResult_News==0)
  {
      $QueryResult_News=mysql_query("select *
                                       from news
                                       by ndate desc limit $Active");
  }

  if ($QueryRow_News=mysql_fetch_array($QueryResult_News))
  {
  	return 1;
  }
  else
  {
    $QueryResult_News=0;
    return 0;
  }
}


function ndate($Args) // переменная ndate
{
  global $QueryRow_News;
  if (isset($QueryRow_News['ndate']))
  {
    return implode('.',array_reverse(explode('-',$QueryRow_News['ndate'],3)));
  }
  else
  {
    return '';
  }
}

function ntitle($Args) // переменная ntitle
{
  global $QueryRow_News;
  if (isset($QueryRow_News['title']))
  {
    return $QueryRow_News['title'];
  }
  else
  {
    return '';
  }
}

function nbody($Args) // переменная nbody
{
  global $QueryRow_News;
  if (isset($QueryRow_News['body']))
  {
    return $QueryRow_News['body'];
  }
  else
  {
    return '';
  }
}

Массивы $Blocks и $Vars:

 
$Blocks=array(array('news','news',0))
$Vars=array('ndate','ntitle','nbody');

Ну вот и все простой шаблонизатор готов, все что я хотел сделал, Вам же теперь его модернизировать и усовершенствовать до тех пор пока он не станет удовлетворять всем Вашим ожиданиям :)

Удачи, искренне Ваш elrevin.




Комментарии

 Ваш комментарий к данному материалу будет интересен нам и нашим читателям!



Последние статьи: Web - программирование / PHP /

GTK+: перспективы развития
02-03-2010   

Библиотека GTK+ прошла долгий путь развития и сейчас очень популярна. GNOME, одна из ведущих оконных сред, использует GTK+ почти исключительно, GIMP построен на GTK+, множество коммерческих разработчиков ПО, таких как Abobe, NVidia и VMware, решили использовать эту библиотеку в качестве графической основы для своих продуктов... подробнее

Кол. просмотров: общее - 4851 сегодня - 1

Новостной портал
13-11-2009   

Slashdot.org – популярный новостной портал с посещаемостью 50 млн. человек в месяц. Авторы проекта добились такого успеха, предоставляя пользователям свежие и интересные новости из мира IT... подробнее

Кол. просмотров: общее - 4761 сегодня - 0

Параллельное выполнение скриптов может нарушить целостность информации в файлах
13-11-2009   

Здесь рассматривается вопрос, что бывает, если запустить некий скрипт почти одновременно (что происходит, например, при большой нагруженности сервера) несколько раз, т.е. запустить несколько копий одного и того же скрипта. И к чему это может привести... подробнее

Кол. просмотров: общее - 4540 сегодня - 0

No spam.php
10-11-2009   

...и снова о спаме. Кто о нем только не писал, и все писали, что это плохо и ай-яй-яй. Я не буду оригинальничать, и тоже скажу – это плохо. Это ай-яй-яй. Как бороться со спамерами со своей стороны... подробнее

Кол. просмотров: общее - 4593 сегодня - 0

Начинаем работу с рисунками в php для Windows
10-11-2009   

Эта статья даст вам общее представление о том, как создавать, обрабатывать и выводить рисунки в PHP4 для Windows... подробнее

Кол. просмотров: общее - 4570 сегодня - 0



  WWW.COMPROG.RU - 2009-2012 | Designed and Powered by Zaipov Renat | Projects