我正在设置一个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');
这显然有效,因为现在路径是绝对的路径,但对我来说似乎真的很奇怪。
这是正常的吗?我应该继续沿着这条路走下去,还是我错过了一些明显的东西?
答案 0 :(得分:13)
通常,标准约定是这样的:就像@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()
函数加载您的类,但这是另一个问题。
答案 1 :(得分:4)
使用配置脚本设置项目的“INSTALL ROOT”,然后使用绝对路径。包含多个包含的相对路径是php中的一个难题。
DEFINE(“INSTALL_ROOT”,“/ path / to / www / project”)
require_once(INSTALL_ROOT。'/ util1.php')
答案 2 :(得分:1)
在我的配置/设置文件中,我执行类似
的操作 define('MYAPP_BASEDIR',realpath('.'));
然后我引用与此相关的所有内容。
...如果您的include目录专门与类文件相关,并且您可以命名它们以便可以从类派生包含文件名,那么您可能希望查看spl_autoload_register()
。
后一部分不是你问题的直接答案,但如果你为你使用的每个课程做了包含,那么它非常方便。
答案 3 :(得分:0)
请记住,它从当前工作目录开始,然后查看包含路径。如果要从某个中心根目录(或许多)引用所有路径,可以在php.ini文件中添加该目录,或者可以使用set_include_path( $path.PATH_SEPERATOR.get_include_path());
答案 4 :(得分:0)
我建议采用抽象策略。
在您的应用程序页面区域中,有一个所有页面都包含的文件。
此“本地”包含文件有一个作业:查找应用程序页面区域之外的包含文件。然后包括那个。它可能就像<?php include dirname(__FILE__).'/../include/include.php/'; ?>
第二个文件是库结构中的单一入口点。它或它包含的其他东西,其工作就是找到所有东西,包括它。
这种结构意味着您只有一个文件作为库的入口点,以及它如何找到库的其余部分不是应用程序页面的问题。这也意味着您的应用程序区域中只有一个文件知道如何查找库的入口点。
如果您需要一种方法让不同的应用程序页面加载不同的东西,我会建议采用模块化方法。这可以是您在master包含之前设置的全局数组,也可以是您可以调用以按名称请求库的函数。是的,这是一个稍微有点方式的主库文件,声明一切都在哪里 - 但它消除了做include LIBRARY_DIR.'/utils/util.php';
的诱惑,直接使得util.php
从utils
移出是不必要的{1}}以及日后的misc/util
。
链接文件的另一个优点是,使代码库可重定位更容易,这使得多个版本可以运行。它可以为应用程序创建一个树,为库创建另一个树。这表示另一个应用程序可以使用您的库。实际上,如果你想进一步帮助隔离,你可以将链接扩展一些。
答案 5 :(得分:0)
你是对的,你的脚本不必知道你的包含的物理路径。
IMO应该在PHP.INI文件中配置包含的位置(如果你预先设置,则为.htaccess)。
Suponse你的包含(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';
答案 6 :(得分:0)
很多人都提供了很好的解决方案,但在谈论包含和要求时,我只提了一个与性能相关的评论。
如果你开始包含'并且需要'很多文件,那么使用include_once或require_once可能很诱人。使用大量_once的高速缓存的脚本表明它们确实会降低性能,因为脚本必须停止其扫描操作,并确保文件尚未包含在内。消除尽可能多的_once可以帮助很多。
答案 7 :(得分:0)
有一个完美的解决方案 - 名为“pwee”的pecl扩展 - 它允许用户使用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>
您应该区分这些包含的情况:
如果是相对路径,请使用以下表格:
require_once "./relative/path/to/script.php";
为什么我使用过去时?因为项目不再受支持 - 仅适用于Php4。如果有人知道支持的类似解决方案,请告诉我。
答案 8 :(得分:0)
最好的方法是构建灵活的自动加载系统。
类名和专有补丁的简单映射。然后不需要任何内部require_ *或include_ *。
自动加载器当然存在相对/绝对路径的问题。好吧,绝对是最系统效率的,所以在我之前提到的数组中,你可以预先添加某种变量{我使用了Phing-style变量},例如。
<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,但之后任何路径都是绝对的。
哦,你可以看到没有文件命名约定或文件布局是强制性的 - 它的巨大优势。
干杯,艾伦。
答案 9 :(得分:0)
似乎每当我将简单脚本从一台服务器移动到另一台服务器时,我都必须重新定义事物的位置。
我在家里设置了一个测试环境,构建了一些东西,然后将它们部署到共享主机上。结果是$_server['DOCUMENT_ROOT']
比一个服务器上的public_html
文件夹高两个文件夹,而另一台服务器上的文件夹高一个文件夹。
这扭曲了我的所有参考资料。所以我尝试$_server['WEB_ROOT']
并再次失败。我以为web根是对服务器上可公开访问的文件夹的根目录的引用,但我错了。
我有一个可以投入一堆非常简单但没有添加大量我不理解的代码的东西(我也不理解这些代码很多,我只是在阅读规则时不断添加并得到了它工作)。
这让我参考了我尝试过的所有三台服务器上可公开访问的Web根目录。现在我可以将我的文件夹移动到任何地方,它只是工作,不需要配置文件!
酒馆-DOC-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");
?>
我的测试环境:
答案 10 :(得分:-1)
为什么不根据它的完整路径要求呢?
例如,/ sharedhost / yourdomain.com / apache / www是您的文档根目录,为什么不使用
require('/sharedhost/yourdomain.com/apache/www/dbutils.php');
这样做的另一个好处是,您可以存储wwwroot的外部,因此它们不太可能被无意中通过网络曝光。
您还可以设置一个等于/sharedhost/yourdomain.com/apache/的全局变量,以便您可以移动网站。
require(WWWROOT . '/dbutils.php');
答案 11 :(得分:-1)
我用
require '../path/to/file.ext';
没问题。
还要求声明不是函数,因此它应该用作
require '/path/to/file.ext';
不
require('/path/to/file.ext');