PHP

Организация структуры сайта

Шаг 1
Основной принцип
В прошлом разделе мы построили кой какой сайтец. И даже прикрутили к нему гостевую книгу. Но этот скрипт нельзя назвать полноценным, потому что там хоть и есть подобие структуры, однако все равно еще много чего перемешано. Не отделяется бизнесс-логика от представления, на каждую страницу все равно нужен отдельный файл в корне, ну и так далее.

По этому, если действительно хотите стать настоящим программистом, забудьте про тот скрипт. Начнем все сначала. Ну а кто начал отсюда - повезло. ))

Жалко? Не нужно жалеть, это всего навсего буквы. Если жалеть каждый неудачно написанный скрипт, толку никогда не выйдет. Мы будем делать настоящие, профессиональные сайты.

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

Есть масса способов организации называемого движка. Это принято называть архитектурой или паттернами (шаблонами проектирования).
Самым популярным на сегодняшний день является паттерн MVC (Model-View-Controller). Ну и начнем отсюда отталкиваться

Не пугайтесь, это не страшно. Я тоже, когда первый раз услышал такое определение, долго плевался и не мог понять, что это за зверь. К тому же в аббревиатуре никакой логики Модель-Вид-Контроллер. Вид то должен быть в конце, а тут все перепутано.

Графическое представление этого безобразия:

которое приведено в википедии, напомнило мне эту картинку:

хотя на самом деле все просто до безумия. Самым жизненным примером этой схемы является обычный телевизор.

Видели когда-нибудь?
Так вот. Сзади у него есть панель с разъёмами. Можно подключить антенну, видеомагнитофон, DVD или даже игровую приставку DANDY. Вот эта панель отвечает за связь с источниками информации либо потребителями. В MVC это называется "МОДЕЛЬ", то есть то, что отвечает за получение или выдачу данных каким то источникам. Базе данных, файловой структуре или еще чего.

Прямо напротив, с аверсной стороны, находится экран. Кинескоп. Или плазма, не важно. Важно, что это устройство позволяет сделать работу телевизора видимой. Это "ВИД" или отображение.

А между ними что то гудит и иногда дымится. Там непонятная куча деталей, которая из полученной информации может сделать кино. Это "КОНТРОЛЛЕР".

Вот и все ужасы. На сайте это выглядит так:

1. Модель - это данные, с которыми работает скрипт. То есть то, что в базе данных или файлах. В общем информация. А так же функции, которые эту информацию получают из источников хранения и передают скрипту. Или наоборот, берут из скрипта и упаковывают для хранения.

2. Вид - это шаблоны. То есть оболочка для информации. Стили, картинки, верстка и прочая красота. А так же функции, которые выбирают нужные шаблоны и вставляют в них нужную информацию.

3. Ну и контроллер - сам скрипт, который готовит блюдо под названием "страница".

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

Схема эта довольно проста как в реализации так и в дальнейшем использовании.

Основные принципы.
1. Полностью разделяем бизнесс-логику с представлением. (Имеется ввиду именно логика и представление, а не php и html)
2. Максимально используется процедурный подход, который более прозрачен.
3. Функционал приложения делится на отдельные, самодостаточные модули.
4. Используется набор общих функций и классов (подобие библиотеки или фреймворка, как угодно)

Как это работает.

Допустим нам нужно сделать главную страницу, и на ней вывести набивший оскомину "Привет, Мир!". Так и сделаем. Вот первый и главный файл:
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml"> 
<head>
<title>Мой сайт</title> 
</head> 
<body> 
Привет, Мир! 
</body> 
</html>

Это у нас банальный HTML. Ничего в нем динамически задать невозможно. Поэтому нам нужен исполняемый файл, то есть .php
Сделаем такой, обозвав его index.php Он по совместительству будет являться точкой входа. Все ссылки на наш сайт будут вести на него. А предыдущий просто включим в него:
[PHP]<?php


/** 
* Подключаем шаблон 
* Includes a template 
*/    
    include './index.tpl';
[/PHP]
Языковые конструкции include, include_once, requre и requre_once позволяют объединить несколько файлов в один. Подробнее про это тут.
Обратите внимание на расширение файла .tpl Теперь это уже не главный файл, а всего навсего шаблон ( англ. template). Это негласное правило, обозначать шаблоны таким расширением. Такие файлы подсвечиваются многими редакторами и сразу видно, что это не готовый HTML а только часть, полуфабрикат.

Чего нам не сиделось на месте, ведь вроде бы ничего не изменилось. Но это пока. А вот сейчас и начнется магия динамических сайтов. Переделаем шаблон так:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">  
<head> 
<title>Мой сайт</title>  
</head>  
<body>  
<?php echo $content ?>  
</body>  
</html>

а index.php так:
<?php


    $content = 'Привет, Мир!'; 
/** 
* Подключаем шаблон 
* Includes a template 
*/    
    include './index.tpl';

Если запустить, то на первый взгляд опять ничего не поменялось, все тот же "Привет, Мир!".
Однако сейчас можно не трогая шаблон, изменить значение переменной $content
$content = 'Привет, Солнце!';

и мы получим совершенно другую картину.
Ну а что PHP умеет менять значения переменных, для нас не новость. Но как же можно вывести в поток значение переменной, если файл у нас вовсе не php, а вообще непонятный tpl какой то...

Все не так плохо.
Дело в том, что любые файлы, подключенные к исполняемым (а именно таковым и является главный индекс), воспринимают дескрипторы как специальные теги, и исполняют код, который находится между ними. Причем это совершенно не влияет на tpl в чистом виде и не мешает править верстку. Так как очень похоже на обычный html тег и не воспринимается браузером, если файл открыть напрямую, без сервера.

На этом принципе основан так называемый native-синтаксис шаблонов. Но нативе предполагает вынос в шаблон логической составляющей, а нам это не подходит. Мы пойдем другим путем (об этом позже).

ВВот и вся основа принципа. Разметка осталось в tpl файлах, а логическая составляющая - в php.

Шаг 2
Буферизация
Однако одного шаблона для полноценного сайта явно недостаточно. Да и выводить голые буквы без разметки в главный шаблон тоже не очень то красиво - нужна разметка. А как же быть, если известно, что разметки не должно быть в файлах php?

Вот тут не помощь приходит одна замечательная особенность PHP. Буферизация.
С явлением буферизации пользователь ПК сталкивается очень часто. Другими словами это простой копи-паст. Когда мы выделяем какой то текст и жмем "копировать", то все, что попало в выделение, записывается в переменную (буфер). А когда жмем "вставить", то вынимаем данные из буфера и вставляем куда нужно.

Так вот PHP умеет делать тоже самое. Сейчас убедимся. Сделаем второй шаблон:
show.tpl
<div style="padding:10px; background-color:#33FFFF;"> 
<h3 style="color:#003399;"><?php echo $salutation ?></h3> 
</div>

а главный индекс перепишем так:
<?php


    ob_start();     
     
    $salutation = 'Привет, мир!'; 
/** 
* Подключаем шаблон приветствия 
* Includes a salutation template 
*/    
    include './show.tpl'; 
         
    $content = ob_get_contents(); 
    ob_end_clean(); 
/** 
* Подключаем шаблон 
* Includes a template 
*/    
    include './index.tpl';

Что тут происходит. Функция ob_start() начинает складывать в буфер весь вывод, который следует после неё. То есть все это не будет отправлено в браузер, а. Так же, как мы выделяем текст. А так, как мы помним, что вместо include можно прописать код из подключенного файла, получится примерно так:
<?php

    ob_start();     
     
    $salutation = 'Привет, мир!'; 
    

<div style="width:300px; padding:10px; margin:20px auto auto 200px;  background-color:#33FFFF;"> 
<h3 style="color:#003399;"><?php echo $salutation ?></h3>

         
    $content = ob_get_contents(); 
    ob_end_clean(); 
/** 
* Подключаем шаблон 
* Includes a template 
*/    
    include './skins/tpl/index.tpl';

Потом функция ob_get_contents() вынимает все оттуда и помещает в переменную $content. То есть похоже на Ctrl+C. Потом функцией ob_end_clean() мы очищаем буфер на всякий случай (весь вывод у нас уже в переменной) и дальше идем в главный шаблон и вставляем все туда:
<body>  
<?php echo $content ?>  
</body>

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

Но для этого нужно создать структуру. Поместим шаблоны в отдельный каталог tpl, а его в другой - skins В него будем складывать все, что касается отображения - стили, картинки, шаблоны и так далее. Это часть паттерна MVC "вид".

Теперь главный индекс будет таким:
<?php


    ob_start();     
     
    $salutation = 'Привет, мир!'; 
/** 
* Подключаем шаблон приветствия 
* Includes a salutation template 
*/    
    include './skins/tpl/show.tpl'; 
         
    $content = ob_get_contents(); 
    ob_end_clean(); 
/** 
* Подключаем шаблон 
* Includes a template 
*/    
    include './skins/tpl/index.tpl';

Вот уже начинает прорисовываться какое то подобие структуры. Что бы её было легче понять, нужно разобраться с файловой системой.

В отдельной директории отображение, а логическая составляющая отдельно. Теперь мы можем одним движением заменить директорию skins и получить совсем другой дизайн, оставив не тронутым весь функционал и все данные. Это и есть разделение бизнесс-логики и представления.

Шаг 3
Модуль динамичeского контента
Теперь задачка посложнее. Нужно сделать так, что бы контент менялся динамически.
А для этого нам нужен логический модуль, который и будет это делать. Не усложняя себе жизнь сделаем так:
<?php
  
/**
* Выбор случайного значения из массива 
* Choice of casual value from a file
*/
    $arr_who = array( 
                       1 => 'Мир', 
                            'Солнце', 
                            'Небо', 
                            'Вася', 
                            'Петя' 
                     ); 
             
           
    
$who = $arr_who[rand(1,count($arr_who))]; 

Если этот код непонятен, пора познакомиться с массивами.

Поместим это в файл index.php но не тот, главный. А отдельный. Это будет индекс модуля.
Вообще идеологически это не совсем верно, называть его индексом. Потому что сам по себе он работать не может. Чуть позже мы исправим это безобразие, а пока просто для того, чтобы обозначить его важность и значимость, пусть будет индексом.

Создадим сам модуль. То есть директорию. И для порядка поместим её в общий каталог модулей.
А раз уж мы начали строить отдельный модуль, то и шаблоны, относящиеся к нему, нужно поместить в свою директорию, созвучную модулю. Тогда будет четко прослеживаться параллель, и ориентироваться в каталогах будет очень легко.

Немного изменим шаблон
show.tpl
<div style=" padding:10px; background-color:#33FFFF;"> 
<h3 style="color:#003399;">Привет, <?php echo $who ?>!</h3> 
</div>

и поместим в новую структуру

Ну и добавим этот модуль в главный индекс
<?php


    ob_start();     
     
/** 
* Подключаем модуль приветствия  
* We connect the greeting module 
*/   
    include './modules/main/index.php';  
     
/** 
* Подключаем шаблон приветствия 
* Includes a salutation template 
*/    
    include './skins/tpl/main/show.tpl'; 
         
    $content = ob_get_contents(); 
    ob_end_clean(); 
/** 
* Подключаем шаблон 
* Includes a template 
*/    
    include './skins/tpl/index.tpl';

Вот и получился у нас динамический контент.

Шаг 4
Навигация
Но нам этого мало, нам нужна полноценная навигация. И куча других страниц. Так за чем дело встало? Сейчас наштампуем сколько душе угодно.
У нас уже есть наметки структуры, ну и разовьем события:

На первый взгляд кажется что запутано, но на самом деле это гораздо проще, чем сваливать кучу файлов в одну корневую директорию и называть их разными именами. По нашей схеме достаточно определиться, какой именно модуль нас интересует. Если это модуль главной страницы, то все логические файлы будут находится в директории main и шаблоны тоже в такой же директории. Соответственно и модуль second

Теперь для наглядности сделаем второй модуль и второй шаблон:
modules/second/index.php
<?php


    $text = 'Вот так примерно и делаются динамические сайты.';

skins/tpl/second/show.tpl
<div style="padding:10px; background-color:#CCCCCC;"> 
<?php echo $text ?> 
</div>

Итак, с отображением страниц определились. Теперь нужно сделать навигацию. Не будем откладывать в долгий ящик:
menu.tpl
<ul> 
<li><a href="?">Главная страница</a></li> 
<li><a href="?">Вторая страница</a></li> 
</ul>

Поместите это в каталог tpl, рядом с главным шаблоном, так как это общее меню и не зависит от подключенного в данный момент модуля.
Ну и потанцуем в главном индексе:
<?php

   
    ob_start();     
     
/** 
* Подключаем меню  
* Includes the menu  
*/   
    include './skins/tpl/menu.tpl';      
      
/** 
* Подключаем модуль приветствия  
* Includes the greeting module 
*/   
    include './modules/main/index.php';      
      
/** 
* Подключаем шаблон приветствия  
* Includes the greeting templates 
*/ 
    include './skins/tpl/main/show.tpl'; 

/** 
* Подключаем модуль второй страницы  
* Includes the module of the second page 
*/   
    include './modules/second/index.php';  
      
/** 
* Подключаем шаблон второй страницы  
* Includes a second templates 
*/ 
    include './skins/tpl/second/show.tpl';  
         
    $content = ob_get_contents(); 
    ob_end_clean(); 
/** 
* Подключаем главный шаблон 
* Includes the basic template 
*/    
    include './skins/tpl/index.tpl';

Запускаем.
Получилось что попало. Оба контента вылезли на страницу и ссылки не работают. Потому что нам нужен переключатель. Переключателем в php является конструкция switch() Вот мы её и применим.
<?php


    ob_start();   
    $page = 'main';
/**   
* Подключаем меню   
* Includes the menu   
*/   
    include './skins/tpl/menu.tpl';   

/** 
* The switch of modules 
* Переключатель страниц 
*/       
    switch($page)  
    {  
/**   
* Подключаем модуль приветствия   
* Includes the greeting module   
*/          
        case 'main':     
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl';  
        break;  
/**   
* Подключаем модуль второй страницы   
* Includes the module of the second page   
*/  
        case 'second': 
            include './modules/second/index.php'; 
            include './skins/tpl/second/show.tpl';  
        break;  
/**   
* Подключаем модуль приветствия по умолчанию  
* Includes the greeting module   
*/            
        default: 
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl'; 
        break;     
    }   

    $content = ob_get_contents();   
    ob_end_clean();   
/**   
* Подключаем главный шаблон   
* Includes the basic template   
*/   
    include './skins/tpl/index.tpl';

Вот. Теперь у нас страницы разделились. Можно прописать в переменную $page вместо 'main' значение 'second' и мы увидим вторую страницу.
Но ссылки так и не работают. Печально.

Шаг 5
Переключение модулей
Исправим казус. Для этого ссылкам нужно придать GET параметр, по которому мы и будем определять, чего юзеру угодно.

menu.tpl
<ul> 
<li><a href="?page=main">Главная страница</a></li> 
<li><a href="?page=second">Вторая страница</a></li> 
</ul>

И примем его на сервере:
<?php


/**  
* Получаем GET переменную   
* Receive GET a variable  
*/  
$page = !empty($_GET['page'])?$_GET['page']:NULL; 


    ob_start();   

/**   
* Подключаем меню   
* Includes the menu   
*/   
    include './skins/tpl/menu.tpl';   

/** 
* The switch of modules 
* Переключатель страниц 
*/       
    switch($page)  
    {  
/**   
* Подключаем модуль приветствия   
* Includes the greeting module   
*/          
        case 'main':     
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl';  
        break;  
/**   
* Подключаем модуль второй страницы   
* Includes the module of the second page   
*/  
        case 'second': 
            include './modules/second/index.php'; 
            include './skins/tpl/second/show.tpl';  
        break;  
/**   
* Подключаем модуль приветствия по умолчанию  
* Includes the greeting module   
*/            
        default: 
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl'; 
        break;     
    }   

    $content = ob_get_contents();   
    ob_end_clean();   
/**   
* Подключаем главный шаблон   
* Includes the basic template   
*/   
    include './skins/tpl/index.tpl';

Запустим, порадуемся и переведем дух.
Что у нас получилось.
1. Логика и представление разведены по разным углам
2. Получилась более-менее внятная структура, которой легко управлять.
3. Имеется возможность смены скина.
Для начала вполне неплохо.

Шаг 6
Организация структуры (продолжение)
Продолжим.
В индексе у нас появилась инициализация переменной, значение которой получается сервером извне. Таких переменных в приложении обычно очень много и нужны они в разных модулях. Чтобы не запутаться и не повториться, переменные стоит инициализировать в отдельном файле.
Файл этот общий и поместить его надо в корень сайта.
variables.php
<?php
  
  
/**
* Получаем GET переменную 
* Receive GET a variable
*/
$page = !empty($_GET['page']) ? $_GET['page'] : NULL;

Соответственно подключить к индексу.
<?php


/** 
* Получаем файл переменных  
* Receive a variables file  
*/ 
    include './variables.php'; 

    ob_start();   

/**   
* Подключаем меню   
* Includes the menu   
*/   
    include './skins/tpl/menu.tpl';   

/** 
* The switch of modules 
* Переключатель страниц 
*/       
    switch($page)  
    {  
/**   
* Подключаем модуль приветствия   
* Includes the greeting module   
*/          
        case 'main':     
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl';  
        break;  
/**   
* Подключаем модуль второй страницы   
* Includes the module of the second page   
*/  
        case 'second': 
            include './modules/second/index.php'; 
            include './skins/tpl/second/show.tpl';  
        break;  
/**   
* Подключаем модуль приветствия по умолчанию  
* Includes the greeting module   
*/            
        default: 
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl'; 
        break;     
    }   

    $content = ob_get_contents();   
    ob_end_clean();   
/**   
* Подключаем главный шаблон   
* Includes the basic template   
*/   
    include './skins/tpl/index.tpl';

Теперь дальше. Что бы нам не запутаться в файлах, ответственных за вывод, нужно их промаркировать. Вот так:
skins/tpl/main/show.tpl
<!-- skins/tpl/main/show.tpl begin -->  

<div style="padding:10px; background-color:#33FFFF;"> 
<h3 style="color:#003399;">Привет, <?php echo $who ?>!</h3> 
</div> 

<!-- skins/tpl/main/show.tpl end -->

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

Еще одна тонкость. Так как у нас есть возможность менять скины, то мы можем сделать мультиязычный сайт, подключая скин на нужном языке.
Но.
В файле modules/main/index.php у нас имеется кириллица, которая полезет на все страницы. Файл этот может быть довольно большим и сложным, делать такие файлы с разными языками и переключать модули по подобию скинов не имеет никакого смысла. По этому все слова, которые должны попасть в вывод, нужно просто заменить константами. Константы эти определять в разных файлах (в зависимости от языка). А вот их уже и подключать по мере надобности. Сделаем в корне еще один каталог (language) и поместим туда файл
language/ru.php
<?php
  

/**
* Варианты модуля приветствия  
* Variants of the module of a greeting
*/  
    define('IRB_WHO_FIRST',  'Мир'); 
    define('IRB_WHO_SECOND', 'Солнце'); 
    define('IRB_WHO_THIRD',  'Небо'); 
    define('IRB_WHO_FOURTH', 'Вася'); 
    define('IRB_WHO_FIFTH',  'Петя');

Изменить язык сайта теперь легко и просто, нужно только изменить путь до языкового файла . Идея стара как бабушка плезиозавра, ныне покойного. В путь вместо названия файла подставим константу, а в неё уже запишем то, что нужно. А для того, что бы настройки были все в одном месте, организуем конфигурационный файл.
config.php
<?php
 

/**
* Choice of language of a site
* Выбор языка сайта
*/ 
    define('IRB_LANGUAGE', 'ru');

index.php
<?php


  
/** 
* We connect a configuration file 
* Подключаем конфигурационный файл 
*/ 
    include './config.php';  

/** 
* We connect a file of the language 
* Подключаем языковой файл 
*/ 
    include './language/'. IRB_LANGUAGE .'.php'; 
     
/** 
* Получаем файл переменных  
* Receive a variables file  
*/ 
    include './variables.php'; 

    ob_start();   

/**   
* Подключаем меню   
* Includes the menu   
*/   
    include './skins/tpl/menu.tpl';   

/** 
* The switch of modules 
* Переключатель страниц 
*/       
    switch($page)  
    {  
/**   
* Подключаем модуль приветствия   
* Includes the greeting module   
*/          
        case 'main':     
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl';  
        break;  
/**   
* Подключаем модуль второй страницы   
* Includes the module of the second page   
*/  
        case 'second': 
            include './modules/second/index.php'; 
            include './skins/tpl/second/show.tpl';  
        break;  
/**   
* Подключаем модуль приветствия по умолчанию  
* Includes the greeting module   
*/            
        default: 
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl'; 
        break;     
    }   

    $content = ob_get_contents();   
    ob_end_clean();   
/**   
* Подключаем главный шаблон   
* Includes the basic template   
*/   
    include './skins/tpl/index.tpl';

Осталось изменить сам модуль, (modules/main/index.php) заменив слова константами:
<?php
  

/**
* Выбор случайного значения из массива 
* Choice of casual value from a file
*/
    $arr_who = array( 
                       1 => IRB_WHO_FIRST, 
                            IRB_WHO_SECOND, 
                            IRB_WHO_THIRD, 
                            IRB_WHO_FOURTH, 
                            IRB_WHO_FIFTH 
                     ); 
            
    
   $who = $arr_who[rand(1,count($arr_who))]; 

Теперь можно не волноваться за вологодский пронос в англоязычном скине. Все слова, попадающие в браузер юзера будут взяты из нужного файла. Если конечно сделать такой:
language/en.php
<?php
   

/**
* Варианты модуля приветствия  
* Variants of the module of a greeting
*/ 
    define('IRB_WHO_FIRST', 'World'); 
    define('IRB_WHO_SECOND','Sun'); 
    define('IRB_WHO_THIRD', 'Sky'); 
    define('IRB_WHO_FOURTH','Vasia'); 
    define('IRB_WHO_FIFTH', 'Petia');

и заменить в конфиге
<?php
 

/**
* Choice of language of a site
* Выбор языка сайта
*/ 
    define('IRB_LANGUAGE', 'en');

Шаг 7
Общие функции и классы
Следующая тонкость. Допустим у нас несколько модулей, которые выводят какие-нибудь даты. И даты эти мы хотим вывести в нужном нам формате. Написать функцию, форматирующую дату проблем не составит, однако её придется переписывать несколько раз в разных модулях. Это лениво. И еще, если эти модули пересекутся, то есть будут подключены одновременно, то будет ошибка повторного определения функции. Что бы этого избежать, такого рода функции и классы нужно выносить в отдельные файлы в отдельном каталоге.
В корне сделайте директорию libs, туда и будем помещать все файлы общих функций и классов. Своего рода фреймворк.

Ну а вот и функция:
libs/default.php
<?php


/** 
* Функция перевода даты из азиатского формата в прописной 
* Translation function of date from the Asian format in the string 
* @param string $date, boolean $format 
* @return string 
*/ 
    function formatDate($date, $format = true)  
    {  
        global $month; 

        $day  = substr($date, 8, 2);          
        $mnt  = $month[substr($date, 5, 2)];         
        $year = substr($date, 0, 4);  
        $time = ''; 
         
        if($format)          
            $time = ' '. substr($date, 11);  

        return $day .' '. $mnt .' '. $year . $time;  
    }

Пока можно сильно не вникать, как она работает. Работает и ладно. Попозже мы все разберем по полочкам. Сейчас важно понять структуру, стратегию так сказать. Тактика потом.

В этом файле можно определить несколько разных функций, которые потребуются в разных модулях. Что бы не переписывать одно и то же.
Останется подключить его к индексу и вызвать функцию там где надо. Добавим в языковой файл массив месяцев, раз они выводятся в браузер:
ru.php
<?php
  

/**
* Варианты модуля приветствия  
* Variants of the module of a greeting
*/
    define('IRB_WHO_FIRST', 'Мир'); 
    define('IRB_WHO_SECOND','Солнце'); 
    define('IRB_WHO_THIRD', 'Небо'); 
    define('IRB_WHO_FOURTH','Вася'); 
    define('IRB_WHO_FIFTH', 'Петя'); 
/**
* Массив месяцев  
* The month array 
*/
    $month = array( 
                    '01' => 'января', 
                    '02' => 'февраля', 
                    '03' => 'марта', 
                    '04' => 'апреля', 
                    '05' => 'мая', 
                    '06' => 'июня', 
                    '07' => 'июля', 
                    '08' => 'августа', 
                    '09' => 'сентября', 
                    '10' => 'октября', 
                    '11' => 'ноября', 
                    '12' => 'декабря' 
                  );

А в файл menu.tpl добавим её вызов:
<!-- skins/tpl/menu.tpl begin --> 
Сегодня <?php echo formatDate(date("Y-m-d"), false) ?> года 
<ul> 
<li><a href="?page=main">Главная страница</a></li> 
<li><a href="?page=second">Вторая страница</a></li> 
</ul> 

<!-- skins/tpl/menu.tpl end -->

Теперь подключим файл общих функций в систему
<?php


/** 
* We connect a configuration file 
* Подключаем конфигурационный файл 
*/ 
    include './config.php';  

/** 
* We connect a file of the language 
* Подключаем языковой файл 
*/ 
    include './language/'. IRB_LANGUAGE .'.php'; 
     
/** 
* Получаем файл переменных  
* Receive a variables file  
*/ 
    include './variables.php'; 
     
/** 
* We connect a file of the general functions 
* Подключаем файл общих функций 
*/  
    include './libs/default.php'; 

    ob_start();   

/**   
* Подключаем меню   
* Includes the menu   
*/   
    include './skins/tpl/menu.tpl';   

/** 
* The switch of modules 
* Переключатель страниц 
*/       
    switch($page)  
    {  
/**   
* Подключаем модуль приветствия   
* Includes the greeting module   
*/          
        case 'main':     
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl';  
        break;  
/**   
* Подключаем модуль второй страницы   
* Includes the module of the second page   
*/  
        case 'second': 
            include './modules/second/index.php'; 
            include './skins/tpl/second/show.tpl';  
        break;  
/**   
* Подключаем модуль приветствия по умолчанию  
* Includes the greeting module   
*/            
        default: 
            include './modules/main/index.php';             
            include './skins/tpl/main/show.tpl'; 
        break;     
    }   

    $content = ob_get_contents();   
    ob_end_clean();   
/**   
* Подключаем главный шаблон   
* Includes the basic template   
*/   
    include './skins/tpl/index.tpl';

и запустим.

Работает? Славно.
Но что мы видим? А видим мы логику в шаблоне вывода. Это предательство и нативе-синтаксис. Не пойдет.

Шаг 8
Логическое завершение
И так, мы логично и последовательно подкрались к популярному в некоторых кругах (их называют угловатыми) native-синтаксису. Вот пример такого шаблона:
<div id="header">Header. <a href="<?php echo WEB_ROOT;?>">Home</a> | 
                <?php if (isset($_SESSION['user'])) :?> 
                    <a href="<?php echo WEB_ROOT;?>?page=logout">Sign out</a> 
                    <?php if (!empty($_SESSION['usermode'])) :?> 
                        | <a href="<?php echo WEB_ROOT;?>?page=clean-usermode">Exit user mode</a> 
                    <?php endif;?> 
                <?php else :?> 
                    <a href="<?php echo WEB_ROOT;?>?page=login">Sign in</a> 
                <?php endif;?> 
            </div>

Практически это php в чистом виде, а где же разделение...
Мы пойдем другим путем. Будем выводить в шаблон исключительно переменные и по одной штуке. Ну и в редком исключении вызовы функций. Это будет похоже на html теги и никакой динамики. Для этого нам понадобится промежуточный файл, который присвоит результаты работы логических файлов переменным. А их уже мы и выведем в шаблон, дабы не шокировать верстальщиков обилием ифов, форов, форечей и прочих таинств программной части. В этом файле, назовем его view.php, мы приводить в порядок вывод, который потребуется на разных страницах. В нашем случае он будет выглядеть так:
libs/view.php
<?php
 

/**
* Date formatting
* Форматирование даты 
*/
    $date = formatDate(date("Y-m-d"), false); 

Теперь, раз уж мы взялись реализовывать паттерн MVC (Model-View-Controller), еще раз немного изменим структуру.

1. Файлам, отвечающим за конкретные действия, вычисления, запросы и т.д, необходимые для формирования нужного функционала, добавим постфикс _controller. То есть если это файл, который формирует приветствие, так как он единственный, называться будет read_controller.php.

Вот и вынесем в него эти вычисления:
modules/main/read_controller.php
<?php


/** 
* Выбор случайного значения из массива  
* Choice of casual value from a file 
*/ 
    $arr_who = array(  
                       1 => IRB_WHO_FIRST,  
                            IRB_WHO_SECOND,  
                            IRB_WHO_THIRD,  
                            IRB_WHO_FOURTH,  
                            IRB_WHO_FIFTH  
                     );           

   $who = $arr_who[rand(1,count($arr_who))]; 

2. За одно, как обещано, исправим историческую несправедливость и переименуем индексы модулей. Называться они теперь будут router.php То есть маршрутизатор.
Почему так. Дело в том, что в модуле может быть несколько контроллеров, это мы рассмотрим позже. А пока просто подготовим почву:
<?php



/**   
* Контроллер формирования случайного обращения  
* The controller of formation of the casual reference  
*/  
    include './modules/main/read_controller.php';  
     
/**   
* Подготовка к выводу  
* Preparation for a conclusion  
*/  
    include './modules/main/view.php';

3. Ну и, как видно из кода, должен быть еще и вид у каждого модуля. Справедливости ради нужно отметить, что это совсем не обязательно. В простых модулях достаточно одного контроллера и незачем делить все это на три. Но мы поделим, что бы привыкнуть к структуре, к тому же нам это пригодится в дальнейшем.

И так, файл modules/main/view.php, непосредственно в модуле. А что бы он не простаивал, подключим в систему дебаггер, который проходили раньше.
<?php


/**   
* Подключаем шаблон   
* Includes a templates   
*/ 
    include './skins/tpl/main/show.tpl'; 
     
    dbg($page);

Ну и второй по аналогии.

А вот так теперь выглядит индекс.
<?php


/**   
* The main router  
* Главный маршрутизатор (роутер)  
* @author IT studio IRBIS-team  
* @copyright © 2009 IRBIS-team  
*/  
/////////////////////////////////////////////////////////  

/**  
* We establish the charset and level of errors  
* Устанавливаем кодировку и уровень ошибок  
*/  
    header("Content-Type: text/html; charset=utf-8");  
    error_reporting(E_ALL);  
      
/**   
* Debug   
* Дебаггер  
* @TODO To clean in release  
*/  
   define('IRB_TRACE', true);     
   include './debug.php'; 


     
/** 
* We connect a configuration file 
* Подключаем конфигурационный файл 
*/ 
    include './config.php';  

/** 
* We connect a file of the language 
* Подключаем языковой файл 
*/ 
    include './language/'. IRB_LANGUAGE .'.php'; 
     
/** 
* Получаем файл переменных  
* Receive a variables file  
*/ 
    include './variables.php'; 
     
/** 
* We connect a file of the general functions 
* Подключаем файл общих функций 
*/  
    include './libs/default.php'; 
     
/** 
* We put in order a conclusion 
* Приводим в порядок вывод 
*/  
    include './libs/view.php'; 
     
     
    ob_start();   

/**   
* Подключаем меню   
* Includes the menu   
*/   
    include './skins/tpl/menu.tpl';   

/** 
* The switch of modules 
* Переключатель страниц 
*/       
    switch($page)  
    {  
/**   
* Подключаем модуль приветствия   
* Includes the greeting module   
*/          
        case 'main':     
            include './modules/main/router.php';             
        break;  
/**   
* Подключаем модуль второй страницы   
* Includes the module of the second page   
*/  
        case 'second': 
            include './modules/second/router.php';  
        break;  
/**   
* Подключаем модуль приветствия по умолчанию  
* Includes the greeting module   
*/            
        default: 
            include './modules/main/router.php'; 
        break;     
    }   

    $content = ob_get_contents();   
    ob_end_clean();   
/**   
* Подключаем главный шаблон   
* Includes the basic template   
*/   
    include './skins/tpl/index.tpl';

Ну и для полноты ощущений добавим в скин папки для картинок и javascript .

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

Всё это может показаться слишком навороченным и совсем ненужным. Так оно и есть, если сайт предполагается из 2-3 страниц. Но когда приложение будет большим и многофункциональным, без структурного подхода будет крайне трудно и разрабатывать и обслуживать сайт. По этому лучше сразу привыкать к структурному мышлению.

Плюсы такого метода.
1. Можно спокойно и непринужденно разрабатывать дополнительный модуль (расширение), а потом за несколько минут внедрить в рабочий сайт.
2. Готовые модули в процессе работы накапливаются и в следующий раз можно просто собрать из них новый сайт как конструктор лего.
3. С шаблонами такого плана справится любой верстальщик, который боится шаблонизаторов или нативе.
4. Шаблоны этого типа можно разрабатывать параллельно с логикой, потому что они друг от друга практически не зависят.
5. Скорость исполнения и ресурсобережливость. По этой схеме в оперативную память грузятся только те файлы, которые действительно принимают участие в формировании данной страницы. И напрочь отсутствует разбор шаблонов с помощью регулярных выражений. А они как известно не самое быстрое явление в php.
6. Прозрачность кода. Структура построена без ООП парадигмы, которая никогда прозрачностью не отличалась. А принцип построения остался практически тем же самым..

Вообще тут показана даже не верхушка айсберга, а только маленький снежок, слепленный на его склоне. На самом деле тонкостей и хитростей у этого подхода очень много, что позволяет делать сайты быстрыми, эффективными и с очень оригинальным функционалом.

Постараемся в следующих уроках более подробно рассказать об этом.
Добавлено: 16 Августа 2013 01:22:29 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...