Я нахожусь в процессе создания php-проекта, но не очень хорошо знаю, как правильно использовать команды include / require php. Теперь мой макет выглядит следующим образом:
/public --apache points into this directory /public/index.php /public/blah/page.php /utils/util1.php -- useful classes/code are stored in other directories out here /dbaccess/db1.php dbaccess/db1.php require '../utils/util1.php
общественности / index.php
require '../dbaccess/db1.php'
общественности / л / page.php
require '../../dbaccess/db1.php'
Проблема заключается в документации php 'include':
Если имя файла начинается с ./ или ../, оно отображается только в текущем рабочем каталоге
Поэтому public / blah / page.php терпит неудачу, поскольку он включает dbaccess / db1.php, который взрывается, когда он пытается включить util1.php. Он терпит неудачу, потому что это относительный путь от исходного сценария в public / blah /, а не от dbaccess /
Это кажется довольно глупым – db1.php должен просто знать, где он включен, из которого не будет работать.
Я видел такие стратегии:
require_once dirname(__FILE__) . '/../utils/util1.php');
Это, по-видимому, работает, так как теперь путь является абсолютным путем, но мне кажется, что это действительно странно.
Это нормально? Должен ли я продолжать этот путь или я пропущу что-то очевидное здесь?
Как правило, стандартные соглашения: например, @grepsedawk, вы хотите определить константу, содержащую корень вашей папки проекта, и если вы можете использовать корень вашей папки include:
define('APP_ROOT', dirname(__FILE__)); define('INCLUDE_ROOT', APP_ROOT . "/includes");
Примечание: имя константы должно быть строкой!
Кроме того, вы заметите, что я использую dirname(__FILE__);
, Если вы поместите файл определения констант в подкаталог, вы можете сделать dirname(dirname(__FILE__));
, что эквивалентно a ../
.
Теперь некоторые другие оговорки. Хотя PATH_SEPARATOR
– холодная константа, она не нужна. Windows принимает / или \ в именах путей, а так как только пользователи Linux / в качестве разделителя путей, продолжайте и всегда используйте / вместо того, чтобы сбрасывать код с повторными ссылками на PATH_SEPARATOR
.
Теперь, когда вы определили свои корневые константы, то, что вы будете делать, когда вам понадобится файл конфигурации, является простым:
include INCLUDE_ROOT . '/path/to/some/file.php';
Вероятно, вам понадобятся ваши постоянные определения ( define(...)
выше) в сценарии начальной загрузки в корневом каталоге:
www_root/ index.php bootstrap.php
Бутстрап будет содержать определения (или include
файла констант), а также include
любых файлов, которые потребуются на КАЖДОЙ странице.
И, наконец, последнее стандартное соглашение, которое вы не можете использовать, но если вы начинаете делать объектно-ориентированное программирование, наиболее распространенный метод (стандарт PEAR) – это назвать ваши классы, используя _ для разделения пространств имен:
class GlobalNamespace_Namespace_Class //...
А затем организуя ваши файловые структуры, сопоставляя пространства имен с подкаталогами (буквально заменяя все _ на / s):
include_dir/ GlobalNamespace/ Namespace/ Class.php
И используя функции __autoload()
для загрузки ваших классов, но это другой вопрос.
У вас есть сценарий конфигурации, который устанавливает «УСТАНОВИТЬ КОРПУС» вашего проекта, а затем использует абсолютные пути. Относительный путь с множественными включениями – головная боль в php.
DEFINE («INSTALL_ROOT», «/ path / to / www / project»)
require_once (INSTALL_ROOT. '/util1.php)
в моем файле конфигурации / установки, я делаю что-то вроде
define('MYAPP_BASEDIR',realpath('.'));
то я ссылаюсь на все относительно этого.
… если ваш каталог include относится конкретно к файлам классов, и вы можете назвать их так, чтобы имя типа include могло быть выведено из класса, вы можете посмотреть в spl_autoload_register()
.
эта последняя часть не является прямым ответом на ваш вопрос, но это очень удобно, если вы делаете включения для каждого класса, который вы используете.
Имейте в виду, он запускается в текущем рабочем каталоге, а затем просматривает включенные пути. Если вы хотите ссылаться на все ваши пути из какого-либо центрального корневого каталога (или многих), вы можете добавить этот каталог в файл php.ini или сделать это программно с помощью set_include_path( $path.PATH_SEPERATOR.get_include_path());
Я предлагаю стратегию абстракции.
В области вашей страницы приложения есть один файл, который включает все страницы.
Этот «локальный» файл включает одно задание: найдите файл include, который находится за пределами области страницы приложения. Затем он включает это. Возможно, это так просто, как <?php include dirname(__FILE__).'/../include/include.php/'; ?>
<?php include dirname(__FILE__).'/../include/include.php/'; ?>
Этот второй файл является единственной точкой входа в вашу библиотечную структуру. Он, или что-то еще, что он включает, имеет задачу найти, где все и в том числе.
Эта структура означает, что у вас есть только один файл в качестве точки входа в вашу библиотеку и как он находит, что остальная часть библиотеки не является проблемой страниц приложения. Это также означает, что у вас есть только один файл в вашей области приложений, который знает, как найти точку входа в вашу библиотеку.
Если вам нужен способ для разных страниц приложения загружать разные вещи, я бы предложил метод модуляции. Это может быть либо глобальный массив, который вы устанавливаете перед включением мастера, либо функцию, которую вы можете вызвать для запроса библиотек по имени. Да, это немного более привлекательный способ вашего файла основной библиотеки, объявляющий константу, где все есть, – но он устраняет искушение делать, include LIBRARY_DIR.'/utils/util.php';
который сразу же делает излишне трудным переместить util.php
из utils
и в misc/util
позднее.
Другим преимуществом связанных файлов является то, что тогда гораздо проще сделать вашу кодовую базу перемещаемой, что позволяет запускать несколько версий. И это позволяет иметь одно дерево для приложения, а другое – для вашей библиотеки. Это означает, что другое приложение может использовать вашу библиотеку. Фактически, вы можете расширить цепочку немного больше, если хотите еще больше помочь в изоляции.
Вы правы, ваши сценарии не обязательно должны знать физический путь, в котором вы включены.
ИМО – место, в которое должны быть настроены параметры include в файле PHP.INI (или .htaccess, если вы предпочитаете).
Предположим, что вы включили (utils и база данных хранятся здесь / home / scott / php_includes /).
PHP.INI:
include_path =.: / дома / Скот / php_includes /
Теперь ваши скрипты могут включать библиотеки следующим образом:
DBAccess / db1.php:
require_once 'utils / util1.php';
общественности / index.php
require_once 'dbaccess / db1.php';
общественности / л / page.php:
require_once 'dbaccess / db1.php';
Многие люди предоставили хорошие решения, но у меня есть только одно замечание, связанное с производительностью, когда речь идет о включении и необходимости.
Если вы начнете включать и требовать много файлов, может возникнуть соблазн использовать include_once или require_once. Cachegrinds скриптов, которые используют множество _once, показали, что они действительно замедляют производительность, так как скрипт должен остановить то, что он делает для сканирования, и убедиться, что файл уже не включен. Устранение, как многие из _once, как вы можете, поможет много.
Было совершенное решение – расширение pecl, называемое «pwee» – это позволило пользователю определить свои собственные суперглобальные константы / переменные extern с использованием XML-файла. Таким образом, вы могли использовать абсолютный путь, как я рекомендую в такой форме:
require_once APP_ROOT."/path/to/your/script.php";
Преимуществом такого решения было:
Файл XML содержал
<Environments> <Application name="www.domain.com" namespace=""> <Constants> <Constant name="APP_ROOT" value="/full/path/to/project/source" /> </Constants> <Constants> <Constant name="WEB_ROOT" value="/full/path/to/project/public" /> </Constants> </Application> </Environments>
ссылка на проект pwee
Вы должны различать эти случаи включения:
В случае относительного пути используйте эту форму:
require_once "./relative/path/to/script.php";
Почему я использую прошедшее время? Поскольку проект не поддерживается больше, он работает только с Php4. Если кто-либо знает подобное решение с поддержкой, сообщите мне.
Лучший способ сделать это – создать гибкую систему автозагрузки.
Простая карта классных имен и проприетарных патчей. Тогда любые внутренние require_ * или include_ * не нужны.
Конечно, имеет значение относительный / абсолютный путь для автозагрузчика. Ну, абсолютный наиболее эффективен с точки зрения системы, поэтому в массиве, о котором я упоминал ранее, вы можете добавить некоторую переменную {я использовал переменную типа Phing}, например
<map> <path classname="MyClass">${project_directory}/libs/my_classes/MyClass.php</path> <path classname="OtherClass">${project_directory}/libs/some_new/Other.php</path> <!-- its so flexible that even external libraries fit in --> <path classname="Propel">${project_directory}/vendors/propel/Propel.php</path> <!-- etc --> </map>
Это xml (также подумайте о файле ini или yaml) и требует компиляции для php во время первого запуска, но после этого любой путь является абсолютным.
О, поскольку вы можете видеть, что соглашение об именах файлов или макет файла не является обязательным – его огромное преимущество.
Привет, Алан.
Кажется, что каждый раз, когда я перемещаю свои простые сценарии с одного сервера на другой, я должен переопределить, где это происходит.
Я создал тестовую среду дома, построил несколько вещей и развернул их на общий хост. Результатом было то, что $_server['DOCUMENT_ROOT']
был на две папки выше, чем папка public_html
на одном сервере, а на другом сервере – одна папка выше.
Это исказило все мои ссылки. Поэтому я попробовал $_server['WEB_ROOT']
и снова не сработал. Я думал, что корень сети был ссылкой на корень общедоступных папок на сервере, но я ошибся.
У меня есть один, чтобы бросить кучу, которая сделала что-то действительно простое, не добавляя много кода, который я не понимаю (я тоже не очень разбираюсь в этом коде, я просто продолжал добавлять, когда читал правила и получал его на работу ).
Это дало мне ссылку на общедоступный веб-корень на всех трех серверах, на которых я его пробовал. Теперь я могу перемещать папку в любом месте, и она просто работает, нет необходимости в файле конфигурации!
паб-док-root.php:
<?php //You only need to paste the following line into your script once, //and it must come before you reference the public document root of your website. //Use $pubroot.'/path_from_public_document_root_to_file/filename.php $pubroot = (str_replace(($_SERVER['PHP_SELF']), '', (str_replace('\\', '/', (realpath(basename(getenv("SCRIPT_NAME")))))))); //uncomment the next line to show the calculated public document root //relative to the document root. //echo ("$pubroot"); ?>
Моя тестовая среда:
Почему бы не потребовать его на основе полного пути?
Например, /sharedhost/yourdomain.com/apache/www – ваш корень вашего документа, поэтому почему бы не использовать
require('/sharedhost/yourdomain.com/apache/www/dbutils.php');
Это также имеет то преимущество, что вы можете хранить свои данные вне вашего wwwroot, чтобы они были гораздо менее подвержены уязвимости через Интернет.
Вы также можете настроить глобальную переменную, равную части /sharedhost/yourdomain.com/apache/, чтобы вы могли перемещать сайт.
require(WWWROOT . '/dbutils.php');
я использую
require '../path/to/file.ext';
без проблем.
Также требуется, чтобы оператор не являлся функцией, поэтому его следует использовать как
require '/path/to/file.ext';
не
require('/path/to/file.ext');