Нужна стратегия включения PHP-файла - PullRequest
11 голосов
/ 04 декабря 2008

Я нахожусь в процессе настройки проекта php, но не очень хорошо знаю, как правильно использовать команды php include / require. Мой макет в настоящее время выглядит так:

/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');

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

Это нормально? Должен ли я продолжать идти по этому пути или я что-то упускаю здесь очевидное?

Ответы [ 12 ]

13 голосов
/ 04 декабря 2008

Обычно стандартные соглашения таковы: как сказал @grepsedawk, вы захотите определить константу, которая содержит корень папки вашего проекта и, если вы можете, корень вашей папки включений:

define('APP_ROOT', dirname(__FILE__));
define('INCLUDE_ROOT', APP_ROOT . "/includes");

Примечание: имя константы должно быть строкой!

Кроме того, вы заметите, что я использую dirname(__FILE__);. Если вы поместите файл определения констант в подкаталог, вы можете сделать dirname(dirname(__FILE__));, что эквивалентно ../.

Теперь несколько других предостережений. Хотя 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
//...

И затем организация вашей файловой структуры, отображающей пространства имен в подкаталоги (буквально заменяя все _ на /):

include_dir/
  GlobalNamespace/
      Namespace/
          Class.php

И использование __autoload() функций для загрузки ваших классов, но это другой вопрос.

4 голосов
/ 04 декабря 2008

Имейте скрипт конфигурации, который устанавливает "INSTALL ROOT" вашего проекта и затем использует абсолютные пути. Относительный путь с множественными включениями - это головная боль в php.

DEFINE ("INSTALL_ROOT", "/ path / to / www / project")

require_once (INSTALL_ROOT. '/Util1.php')

1 голос
/ 04 декабря 2008

в моем файле конфигурации / настройки, я делаю что-то вроде

define('MYAPP_BASEDIR',realpath('.'));

тогда я ссылаюсь на все относительно этого.

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

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

0 голосов
/ 13 мая 2010

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

Я создал тестовую среду дома, собрал несколько вещей и развернул их на общем хосте. В результате $_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");
?>

Моя тестовая среда:

  • php 5.3.1
  • Apache 2.2.14 (Win32) mod_ssl 2.2.14 OpenSSL 0.9.8k
  • ZendServer-CE-5.0.0GA_RC181-5.3.1-Windows_x86
0 голосов
/ 28 декабря 2008

Лучший способ сделать это - создать гибкую систему автозагрузки.

Простая карта имен классов и патчей. Тогда любые внутренние 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 при первом запуске, но после этого любой путь является абсолютным.

О, как вы можете видеть, соглашение об именовании файлов не является обязательным, или макет файла является обязательным - его огромное преимущество.

Приветствия, Алан.

0 голосов
/ 19 декабря 2008

Было совершенное решение - расширение pecl под названием "pwee" - оно позволяло пользователю определять свои внешние суперглобальные константы / переменные с использованием файла 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

Следует выделить следующие случаи включения:

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

В случае относительного пути используйте эту форму:

  require_once "./relative/path/to/script.php";

Почему я использую прошедшее время? Потому что проект больше не поддерживается - работает только с Php4. Если кто-нибудь знает подобное решение с поддержкой, пожалуйста, сообщите мне.

0 голосов
/ 04 декабря 2008

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

Если вы начинаете включать и требовать много файлов, может возникнуть соблазн использовать include_once или require_once. Cachegrinds скриптов, которые используют много _once, показали, что они действительно замедляют производительность, так как скрипт должен остановить то, что он делает для сканирования и убедиться, что файл еще не был включен. Ликвидация как можно большего количества _once'ов очень поможет.

0 голосов
/ 04 декабря 2008

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

IMO местоположение, где находятся включения, должно быть настроено в файле PHP.INI (или .htaccess, если вы предпочитаете).

Suponse ваши включает (утилиты и базы данных хранятся здесь /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';

0 голосов
/ 04 декабря 2008

Я предлагаю стратегию абстракции.

  1. В области страниц приложения есть один файл, который включают все страницы.

  2. У этого «локального» включаемого файла есть одно задание: найти включаемый файл, который находится за пределами области страницы приложения. Затем он включает это. Это может быть так просто, как <?php include dirname(__FILE__).'/../include/include.php/'; ?>

  3. Этот второй файл является единственной точкой входа в структуру вашей библиотеки. Он или что-то еще включает в себя поиск того, где все находится, и включая его.

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

Если вам нужен способ для разных страниц приложения загружать разные вещи, я бы предложил модульный подход. Это может быть либо глобальный массив, который вы установили перед включением мастера, либо функция, которую вы можете вызвать для запроса библиотек по имени. Да, это немного более причудливый способ, которым ваш файл основной библиотеки объявляет константу того, где все находится, - но он устраняет искушение делать include LIBRARY_DIR.'/utils/util.php';, что сразу делает излишне трудным перемещение util.php из utils и в misc/util позднее.

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

0 голосов
/ 04 декабря 2008

Помните, что он начинается в текущем рабочем каталоге, а затем просматривает пути включения. Если вы хотите сослаться на все ваши пути из некоторого центрального корневого каталога (или многих), вы можете добавить этот каталог в файл php.ini или сделать это программно с помощью set_include_path( $path.PATH_SEPERATOR.get_include_path());

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...