Даешь объектно-ориентированное программирование!
Автор: Dmitry Vereschaka (dmitry.rsl.ru)
Программисты - народ ленивый. Поэтому, когда дело доходит
до работы, они сначала ищут в сети какой-нибудь программный продукт,
который в той или иной степени удовлетворяет их потребности в решении
поставленной задачи. Если программист пишет что-то на PHP, то одной из
первых систем, которые он найдёт, будет PHP Nuke. Поигравшись с ним
некоторе время, программист понимает, что вещь, конечно, хорошая, но
слишком уж "коряво" написанная, тяжело адаптируемая к задачам, отличных от
web-портала, да и перевод на русский язык сделан человеком, имевшем не
более трёх очков по великому могучему.
Тем не менее, подход к хранению кода в том виде, как это
реализовано в PHP Nuke и описано на большом количестве сайтов, посвящённым
PHP, кажется вполне логичным, доступным и приемлимым.
Общая схема этого похода, называемого "модульным",
такова: Существует некий главный скрипт, например index.php. Этот скрипт в
неком параметре, например, $module, принимает имя модуля, который отдаёт
браузеру какую-нибудь страницу. index.php выглядит примерно таким образом:
<?php
include "config.php";
if (!$module ||
!file_exists("modules/$module.inc.php")) {
$module="default";
}
include
"modules/$module.inc.php";
?>
Типичный "модуль" при таком построении сайта выглядит
так:
<?php
if (!eregi("index.php",
$PHP_SELF)) { die ("Access denied"); }
$page_title="..."; //
устанавливаем имя страницы
include
"includes/header.php"; // подключаем дизайн
// некий php - код, который
генерирует данную страницу
include
"includes/footer.php"; // подключаем остатки дизайна
?>
Вроде бы всё хорошо, однако есть некоторые но:
В кажом модуле нужно делать include заголовка - иначе не
сможем изменить и другие тэги в начале страницы.
В кажом модуле необходимо делать
if (!eregi("index.php",
$PHP_SELF)) { die ("Access denied"); }
- чтобы не вызвали напрямую, миновав различную
инициализацию переменных, подключение к СУБД, include общих функций и т.д.
в config.php. Хотя, на самом деле, такой запрет делается тремя строчками в
.htaccess:
<files *.php>
deny from all
</files>
В каждом модуле надо делать include нижней части страницы
- по той же причине, что и п.1
При программировании модулей приходиться многократно
вызывать одни и те же процедуры: генерацию меню, навигации, банеров,
голосований и т.д. Даже если все эти процедуры будут с красивыми,
легкозпоминаемыми именами, с небольшим количеством параметров, будут
содержать всё HTML-форматирование внутри себя, то всё равно каждый раз при
написании модуля надо будет последовательно написать вызовы всех этих
процедур:
<?php
PageNavigation(module
params);
PageLeftMenu(module
params);
// PHP-код, генерирующий
контент
PageRelatedLinks(module
params);
PageNewsLinks(module
params);
PageVotes(module params);
PageBanner(module params);
?>
Другие но, забытые как страшный сон
Таким образом, написание нового модуля начинается с
копирования текста старого модуля с последующим исправлением блока,
ответственного за контент.
Однако есть способ избавить себя от этого монотонного,
длительного и никому не нужного процесса - для этого нужно вспомнить о
существовании ООП (объектно-ориентированного программирования) и о том,
что PHP очень неплохо это самое ООП поддерживает.
Для начала создадим класс - Web-страницу, в которой
опишем все фунции, используемые при генерации наших страниц:
class WebPage
{
// если имя функции
совпадает с именем класса, то она считается конструктором
// говоря по-русски, она
выполняется при создании объекта
function WebPage($module)
{
$this->page_title="демо-модуль";
}
function PageHeader()
{
include
"includes/header.inc.php";
// в этом файле вместо
<?=$page_title;?> надо будет написать
<?=$this->page_title;?>
}
function PageFooter()
{
include
"includes/footer.inc.php";
}
function PageNavigation()
{
// Код для навигации
}
function PageLeftMenu()
{
// Код для меню в левой
части страницы
}
function PageContent()
{
// Код, генерирующий
контент
}
function PageRelatedLinks()
{
// Код, генерирующий ссылки
на связанные разделы
}
function PageNewsLinks()
{
// Код, генерирующий блок
новостей
}
function PageVotes()
{
// Код, генерирующий блок
голосований
}
function PageBanner()
{
// Код, генерирующий баннер
}
function Run()
// ф-я Run последовательно
вызывает все необходимые
// методы класса WebPage
для построения страницы
{
$this->PageNavigation();
$this->PageLeftMenu();
$this->PageContent();
$this->PageRelatedLinks();
$this->PageNewsLinks();
$this->PageVotes();
$this->PageBanner();
}
}
?>
Теперь, если нам надо сделать, например, страницу,
которая отличается отстандартной только блоком контента, то мы можем
определить новый класс, производный от WebPage:
class CoolPage extends
WebPage
{
// переопределяем
конструктор, чтобы изменить имя модуля
function CoolPage()
{
// вызываем конструктор
родительского класса - вдруг он что-то полезное делает? ;)
parent::WebPage();
$this->page_title="Крутой модуль";
}
function PageContent()
{
// выводим контент
}
}
если нам на странице не нужны новости, то мы определяем
другой класс:
class CoolPageWithoutNews
extends CoolPage
{
// здесь мы не описываем
фунцию CoolPageWithoutNews
// в этом случае PHP
автоматически вызовет конструктор родительского класса
// соответственно имя нашей
страницы будет "крутой модуль"
function PageNewsLinks()
{
// тут пусто, чтобы ссылки
на новости не выводились
}
}
и так далее.
В принципе, если у вас появляется большое количество
классов, то код каждого из ни их тоже можно разместить в отдельном файле,
однако следует следить за тем, чтобы классы, у которых есть производные
классы, были доступны всегда, иначе PHP не сможет понять, из какого файла
брать код родительского класса.
Вот пример файла index.php, который может выступать в
качестве "главного файла":
<?php
include "config.php";
include "base_classes.php";
if ($module &&
file_exists($file="modules/$module.inc.php")) {
// проверяем, есть ли файл
с "телом" класса
include $file;
}
if (!class_exists($module))
{
// проверяем, что класс
существует
$module="WebPage";
}
$page=new $module; //
создаём объект
$page->Run(); //
запускаем генерацию страницы
}
?>
Примечание: не смотря на то, что весь приведённый выше
код ни разу не запускался, вышеуказанная технология, с той разницей, что
почти вся информация находится в БД, реально эксплуатируется, например, на
моём сайте.