PHP включает файловую стратегию

Я занимаюсь настройкой 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. Он терпит неудачу, потому что это относительный путь от исходного script в public/blah/, а не от dbaccess/

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

Я видел такие стратегии:

require_once dirname(__FILE__) . '/../utils/util1.php');

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

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

Ответ 1

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

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(...) выше) в начальной загрузке script в корневом каталоге:

www_root/
  index.php
  bootstrap.php

Бутстрап будет содержать определения (или include файла констант), а также include любых файлов, которые потребуются на КАЖДОЙ странице.

И, наконец, последнее стандартное соглашение, которое вы не можете использовать, но если вы начнете выполнять объектно-ориентированное программирование, наиболее распространенный метод (стандарт PEAR) - это назвать ваши классы, используя _ для разделения пространств имен:

class GlobalNamespace_Namespace_Class
//...

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

include_dir/
  GlobalNamespace/
      Namespace/
          Class.php

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

Ответ 2

У вас есть конфигурация script, которая устанавливает "УСТАНОВИТЬ КОРПУС" вашего проекта, а затем использует абсолютные пути. Относительный путь с несколькими включениями - головная боль в php.

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

require_once (INSTALL_ROOT. '/util1.php)

Ответ 3

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

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

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

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

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

Ответ 4

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

Ответ 5

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

  • В области вашей страницы приложения укажите один файл, содержащий все страницы.

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

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

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

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

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

Ответ 6

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

IMO, где должны быть настроены параметры 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';

Ответ 7

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

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

Ответ 8

Было совершенное решение - расширение 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

Вы должны различать эти случаи включения:

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

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

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

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

Ответ 9

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

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

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

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

Ответ 10

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

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

Ответ 11

Почему бы не потребовать его на основе полного пути?

Например,/sharedhost/yourdomain.com/apache/www является вашим корнем для документов, поэтому почему бы не использовать

require('/sharedhost/yourdomain.com/apache/www/dbutils.php');

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

Вы также можете настроить глобальную переменную, равную части /sharedhost/yourdomain.com/apache/, чтобы вы могли перемещать сайт.

require(WWWROOT . '/dbutils.php');

Ответ 12

Я использую

require '../path/to/file.ext';

без проблем.

Также требуется инструкция, а не функция, поэтому ее следует использовать как

require '/path/to/file.ext';

не

require('/path/to/file.ext');