2.10 Инструкции require и include

Инструкции require и include
Эти инструкции позволяют разбить текст программы на несколько файлов. Рассмотрим, например, require. Ее формат такой:
require имя_файла;
При запуске программы интерпретатор просто заменит инструкцию на содержимое файла имя_файла (этот файл может также содержать сценарий на PHP, обрамленный, как обычно, тегами <?php и ?>). Это бывает довольно удобно для включения в вывод сценария всяких “шапок” с HTML-кодом.

Шапка. Файл require/head.html
<!DOCTYPE html>
<html lang=”ru”>
<head>
<title>Демонстрация конструкции require</title>
<meta charset=’utf-8′>
</head>
<body>
<b><pre>
Тело скрипта. Файл require/script.php
<?php ## Тело скрипта
require “head.html”;
print_r($GLOBALS);
require “foot.html”;
?>
Подвал. Файл require/foot.html
<!– “Подвал”. –>
</pre></b>
&copy;Warner Bros., 1999.
</body></html>

Безусловно, это лучше, чем включать весь HTML-код в сам сценарий вместе с инструкциями программы. Вам скажет спасибо тот, кто будет пользоваться вашей программой и захочет изменить ее внешний вид. Однако, несмотря на кажущееся удобство, это
все же плохая практика. Действительно, наш сценарий разрастается аж до трех файлов! А как было сказано выше, чем меньше файлов использует программа, тем легче с ней будет работать вашему дизайнеру и верстальщику (которые о PHP имеют слабое представление). О том, как же быть в этой ситуации, мы расскажем в главе 50, посвященной технике разделения кода и шаблона сценария. Инструкция include практически идентична require, за исключением того, что в случае невозможности включения файла работа сценария не завершается немедленно, а продолжается (с выводом соответствующего диагностического сообщения). В большинстве случаев вряд ли ее использование окажется целесообразным.

ВНИМАНИЕ!
Старайтесь не использовать инструкции require и include для подключения других частей кода к PHP-программе! Применяйте их только в целях разделения HTML-страниц на “шапки” и “подвалы”. Для того чтобы подключить другую часть скрипта, используйте инструкцию require_once, описанную в разд. “Решение: require_once” далее в этой главе.

Инструкции однократного включения
Большие и сложные сценарии обычно состоят из не одного десятка файлов, включающих друг друга. Поэтому в скриптах (особенно старых) приходится встречать неоднократное применение инструкций include и require. При этом возникает проблема: становится довольно сложно контролировать, как бы случайно не включить один и тот же файл несколько раз (что чаще всего приводит к ошибке).
Суть проблемы
Чтобы стало яснее, мы расскажем вам притчу. Как-то раз разработчик Билл написал несколько очень полезных функций для работы с файлами Microsoft Excel и решил объединить их в библиотеку — файл xllib.php.
Библиотека для работы с Excel. Файл trouble/xllib.php
<?php ## Библиотека для работы с Excel
function LoadXlDocument($filename) { /* . . . */ }
function SaveXlDocument($filename,$doc) { /* . . . */ }
?>
Разработчик Вася захотел сделать то же самое для работы с документами Microsoft Word, в результате чего на свет явилась библиотека wlib.php. Так как Word и Excel связаны между собой, Вася использует в своей библиотеке (листинг 9.11) возможности,
предоставляемые библиотекой xllib.php — подключает ее командой require.
Библиотека для работы с Word. Файл trouble/wlib.php
<?php ## Библиотека для работы с Word
require “xllib.php”;
function LoadWDocument($filename) { /* . . . */ }
function SaveWDocument($filename,$doc) { /* . . . */ }
?>
Обе библиотеки стали настолько популярны в среде Web-программистов, что скоро все стали внедрять их в свои программы. При этом, конечно же, никому нет дела до того, как эти библиотеки на самом деле устроены — все просто подключают их к своим сце-
нариям при помощи require, не задумываясь о возможных последствиях.
Но в один прекрасный день одному неизвестному программисту потребовалось работать и с документами Word, и с документами Excel. Он, недолго думая, подключил к своему сценарию обе библиотеки.
Ошибка в скрипте. Файл trouble/aargh.php
<?php ## Возникает ошибка!
require “wlib.php”;
require “xllib.php”;
$wd = LoadWDocument(“document.doc”);
$xd = LoadXlDocument(“document.xls”);
?>
Каково же было его удивление, когда при запуске этого сценария он получил сообщение об ошибке, в котором говорилось, что в файле xlib.php функция LoadXlDoc() определена дважды! Вот точный текст ошибки:
Cannot redeclare loadxldocument() (previously declared in xllib.php:2) in xllib.php on line 2
Что же произошло? Нетрудно догадаться, если проследить за тем, как транслятор PHP “разворачивает” код листинга 9.12. Вот как это происходит:
//require “wlib.php”;
//require “xllib.php”;
function LoadXlDocument($filename) { /* . . . */ }
function SaveXlDocument($filename,$doc) { /* . . . */ }
function LoadWDocument($filename) { /* . . . */ }
function SaveWDocument($filename,$doc) { /* . . . */ }
//require “xllib.php”;
function LoadXlDocument($filename) { /* . . . */ }
function SaveXlDocument($filename,$doc) { /* . . . */ }
$wd = LoadWDocument(“document.doc”);
$xd = LoadXlDocument(“document.xls”);
Как видим, файл xllib.php был включен в текст сценария дважды: первый раз косвенно через wlib.php и второй раз — непосредственно из программы. Поэтому транслятор, дойдя до выделенной строки, обнаружил, что функция LoadXlDocument() определяется второй раз, на что честно и прореагировал.
Конечно, разработчик сценария мог бы исследовать исходный текст библиотеки wlib.php и понять, что во второй раз xllib.php включать не нужно. Но согласитесь — это не выход. Действительно, при косвенном подключении файлов третьего и выше уровней вполне могут возникнуть ситуации, когда без модификации кода библиотек будет уже не обойтись. А это недопустимо. Как же быть?
Решение: require_once
Что ж, после столь длительного вступления (возможно, слишком длительного?) наконец настала пора рассказать, что думают по этому поводу разработчики PHP. А они предлагают простое решение: инструкции require_once и include_once. Инструкция require_once работает точно так же, как и require, но за одним важным исключением. Если она видит, что затребованный файл уже был ранее включен, то ничего не делает. Разумеется, такой метод работы требует от PHP хранения полных имен всех подсоединенных файлов где-то в недрах интерпретатора. Так он, собственно говоря, и поступает. Вы можете самостоятельно заменить в приведенных выше сценариях все вызовы require на require_once и убедиться, что после этого сообщение об ошибке перестанет выдаваться.
Инструкция include_once работает совершенно аналогично, но в случае невозможности найти включаемый файл работа скрипта продолжается, а не завершается немедленно.

ЗАМЕЧАНИЕ
Как мы уже говорили, в PHP существует внутренняя таблица, которая хранит полные имена всех включенных файлов. Проверка этой таблицы осуществляется инструкциями include_once и require_once. Однако добавление имени включенного файла производят
также и функции require и include. Поэтому, если какой-то файл был востребован, например, по команде require, а затем делается попытка подключить его же, но с использованием require_once, то последняя инструкция просто проигнорируется.

Везде, где только возможно, применяйте инструкции с суффиксом once. Постарайтесь вообще отказаться от require и include. Это упростит разбиение большой и сложной программы на относительно независимые модули.

Залишити відповідь