绝对路径 vs 相对路径

14
如果我使用绝对路径,我就不能将整个目录移动到新位置。如果我使用相对路径,我就不能将单个文件移动到新位置。
那么这里的解决方案是什么呢?是设置一个包含根路径的配置文件并从那里开始吗?还是有一个规则:永远不要移动文件?
我在一些项目中看到人们使用dirname(FILE)。那么它的意义是什么,我的意思是,为什么不直接忽略它,因为dirname已经是相对的了(取决于文件所处的位置)?

使用dirname(__FILE__)__DIR__的好处是,即使文件被包含在其他文件中,它仍将返回当前脚本的目录。如果您有一个包含dir/script.php的文件,则script.php中的默认包含路径将是根目录而不是dir/。 - Kokos
1
@Frank Vilea:你是否设置了一个包含根路径的配置文件,然后从那里开始? 是的 - Luca Filosofi
我个人在这方面并不擅长,但我猜想思路就是将这两者混合起来。通过在主脚本中添加绝对路径,并在文件包含和脚本中使用的地方添加相对路径。当然,你不能仅仅使用相对路径移动文件而不改变相对路径声明中的任何内容。 - OptimusCrime
我在这里同意 @aSeptik 的观点,将根路径存储在配置文件中是通常最好的解决方案。 - Nick
5个回答

15

你应该使用一个配置文件,在每个文件的第一行进行包含。例如,你的应用程序看起来像这样:

root / App / Plugins

在你的根目录中:app-config.php

if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');

现在,假设你需要包含一个插件文件,那么

在你的插件目录中:my-plugin.php

require_once '../../app-config.php';

现在这条线下的所有内容都可以使用ABSPATH

例如,你想要加载一张图片

<img src='".ABSPATH."Public/images/demo.png' alt=''/>

现在,如果你的应用程序被设计为自动加载一些文件,那么事情就更简单了

plugin-widget-1.php

这样,my-plugin.php 文件或由其加载的任何其他文件中的所有内容都可以使用 ABSPATH,而无需每次都包含 app-config.php 文件。

有了这个想法,您可以在 app-config.php 示例中随意使用所有简写。

define('UPLOAD_PATH', ABSPATH. 'Public/uploads/');
define('IMAGES_PATH', ABSPATH. 'Public/images/');
define('HELPERS_PATH', ABSPATH. 'App/helpers/');
...

所以,现在你已经都定义好了,如果你需要移动一个文件,比如往前移动一个文件夹,例如:

root / App / Plugins / Utils

只需包含 require_once '../../../app-config.php';

显然,我假设你每次不会更改路径 =) 无论如何,如果你需要这样做,更改一个文件包含总比更改数百个要简单。

希望这对你有意义 =)


2
我曾在一些项目中看到人们使用dirname(FILE)。那有什么意义呢?我的意思是,既然dirname与文件所在位置有关,为什么不直接把它省略掉呢?无论如何,它都是相对于包含路径的。dirname(__FILE__)(或者在PHP >=5.3中只需使用__DIR__)可以使你从任何位置运行该文件。如果您使用相对路径,则值“。”可能会改变。请参见: berry@berry-pc:~% cat so.php
<?php
var_dump( realpath( '.' ) );
var_dump( realpath( __DIR__ ) );

berry@berry-pc:~% php so.php

string(11) "/home/berry"
string(11) "/home/berry"

berry@berry-pc:~% cd foo

切换到foo目录。

berry@berry-pc:~/foo% php ../so.php

在当前目录下执行../so.php的php文件。

string(15) "/home/berry/foo"
string(11) "/home/berry"

因此,它是相对的,但是相对于当前工作目录,而不是文件所在的目录。这就是为什么你会想要使用__DIR__。顺便说一下; 是的,我不经常移动文件。如果我确实移动了文件,那么我就必须更新对该文件的每个调用,尽管我现在不再需要或包含很多内容,因为我正在使用Autoloader

至于我提到的其他文件(如模板文件),我手动设置路径,但只需一次。然后我引用$path . '/filename.php';,这样以后更容易更改。


2
感谢您提供如此详细的帖子,现在一切都清晰了。另外,自动加载功能似乎非常不错。 - Frank Vilea

1

根据您的使用情况,定义一个常量来保存应用程序路径是一种常见做法。

不要使用变量,因为它可能会在应用程序中某个地方被覆盖,从而导致应用程序崩溃。

最好结合符号链接(symbolic)创建分支。

application dirs
===============================
/home/latest         -> symlink
/home/testing        -> symlink
/home/20111202000000 -> latest development version
/home/20111201000000 -> yesterday stable release

因此,您可以符号链接 / home / testing -> / home / 20111202000000,同时保持稳定版本 / home / latest -> / home / 20111201000000。

有了这个,您无需冒着破坏生产站点的风险进行一些测试/开发,并且可以轻松地转移开发目录。


1

我总是使用绝对路径,但我也会在每个自定义PHP项目中使用启动文件,其中我会根据从$_SERVER提取的值来将最常用的路径定义为常量。

以下是我如何定义我的根路径:

define("LOCAL_PATH_ROOT", $_SERVER["DOCUMENT_ROOT"]);
define("HTTP_PATH_ROOT", isset($_SERVER["HTTP_HOST"]) ? $_SERVER["HTTP_HOST"] : (isset($_SERVER["SERVER_NAME"]) ? $_SERVER["SERVER_NAME"] : '_UNKNOWN_'));

路径LOCAL_PATH_ROOT是文档根目录。路径HTTP_PATH_ROOT是通过HTTP访问同一路径时的等效路径。

在此时,可以使用以下代码将任何本地路径转换为HTTP路径:

str_replace(LOCAL_PATH_ROOT, RELATIVE_PATH_ROOT, $my_path)

如果您想确保与基于Windows的服务器兼容,您需要将目录分隔符替换为URL分隔符:
str_replace(LOCAL_PATH_ROOT, RELATIVE_PATH_ROOT, str_replace(DIRECTORY_SEPARATOR, '/', $my_path))

这是我使用的完整Bootstrap代码,用于PHP PowerTools模板

defined('LOCAL_PATH_BOOTSTRAP') || define("LOCAL_PATH_BOOTSTRAP", __DIR__);

// -----------------------------------------------------------------------
// DEFINE SEPERATOR ALIASES
// -----------------------------------------------------------------------
define("URL_SEPARATOR", '/');
define("DS", DIRECTORY_SEPARATOR);
define("PS", PATH_SEPARATOR);
define("US", URL_SEPARATOR);

// -----------------------------------------------------------------------
// DEFINE ROOT PATHS
// -----------------------------------------------------------------------
define("RELATIVE_PATH_ROOT", '');
define("LOCAL_PATH_ROOT", $_SERVER["DOCUMENT_ROOT"]);
define("HTTP_PATH_ROOT",
        isset($_SERVER["HTTP_HOST"]) ?
        $_SERVER["HTTP_HOST"] : (
        isset($_SERVER["SERVER_NAME"]) ?
        $_SERVER["SERVER_NAME"] : '_UNKNOWN_'));

// -----------------------------------------------------------------------
// DEFINE RELATIVE PATHS
// -----------------------------------------------------------------------
define("RELATIVE_PATH_BASE",
        str_replace(LOCAL_PATH_ROOT, RELATIVE_PATH_ROOT, getcwd()));
define("RELATIVE_PATH_APP", dirname(RELATIVE_PATH_BASE));
define("RELATIVE_PATH_LIBRARY", RELATIVE_PATH_APP . DS . 'vendor');
define("RELATIVE_PATH_HELPERS", RELATIVE_PATH_BASE);
define("RELATIVE_PATH_TEMPLATE", RELATIVE_PATH_BASE . DS . 'templates');
define("RELATIVE_PATH_CONFIG", RELATIVE_PATH_BASE . DS . 'config');
define("RELATIVE_PATH_PAGES", RELATIVE_PATH_BASE . DS . 'pages');
define("RELATIVE_PATH_ASSET", RELATIVE_PATH_BASE . DS . 'assets');
define("RELATIVE_PATH_ASSET_IMG", RELATIVE_PATH_ASSET . DS . 'img');
define("RELATIVE_PATH_ASSET_CSS", RELATIVE_PATH_ASSET . DS . 'css');
define("RELATIVE_PATH_ASSET_JS", RELATIVE_PATH_ASSET . DS . 'js');

// -----------------------------------------------------------------------
// DEFINE LOCAL PATHS
// -----------------------------------------------------------------------
define("LOCAL_PATH_BASE", LOCAL_PATH_ROOT . RELATIVE_PATH_BASE);
define("LOCAL_PATH_APP", LOCAL_PATH_ROOT . RELATIVE_PATH_APP);
define("LOCAL_PATH_LIBRARY", LOCAL_PATH_ROOT . RELATIVE_PATH_LIBRARY);
define("LOCAL_PATH_HELPERS", LOCAL_PATH_ROOT . RELATIVE_PATH_HELPERS);
define("LOCAL_PATH_TEMPLATE", LOCAL_PATH_ROOT . RELATIVE_PATH_TEMPLATE);
define("LOCAL_PATH_CONFIG", LOCAL_PATH_ROOT . RELATIVE_PATH_CONFIG);
define("LOCAL_PATH_PAGES", LOCAL_PATH_ROOT . RELATIVE_PATH_PAGES);
define("LOCAL_PATH_ASSET", LOCAL_PATH_ROOT . RELATIVE_PATH_ASSET);
define("LOCAL_PATH_ASSET_IMG", LOCAL_PATH_ROOT . RELATIVE_PATH_ASSET_IMG);
define("LOCAL_PATH_ASSET_CSS", LOCAL_PATH_ROOT . RELATIVE_PATH_ASSET_CSS);
define("LOCAL_PATH_ASSET_JS", LOCAL_PATH_ROOT . RELATIVE_PATH_ASSET_JS);

// -----------------------------------------------------------------------
// DEFINE URL PATHS
// -----------------------------------------------------------------------
if (US === DS) { // needed for compatibility with windows
    define("HTTP_PATH_BASE", HTTP_PATH_ROOT . RELATIVE_PATH_BASE);
    define("HTTP_PATH_APP", HTTP_PATH_ROOT . RELATIVE_PATH_APP);
    define("HTTP_PATH_LIBRARY", false);
    define("HTTP_PATH_HELPERS", false);
    define("HTTP_PATH_TEMPLATE", false);
    define("HTTP_PATH_CONFIG", false);
    define("HTTP_PATH_PAGES", false);
    define("HTTP_PATH_ASSET", HTTP_PATH_ROOT . RELATIVE_PATH_ASSET);
    define("HTTP_PATH_ASSET_IMG", HTTP_PATH_ROOT . RELATIVE_PATH_ASSET_IMG);
    define("HTTP_PATH_ASSET_CSS", HTTP_PATH_ROOT . RELATIVE_PATH_ASSET_CSS);
    define("HTTP_PATH_ASSET_JS", HTTP_PATH_ROOT . RELATIVE_PATH_ASSET_JS);
} else {
    define("HTTP_PATH_BASE", HTTP_PATH_ROOT .
            str_replace(DS, US, RELATIVE_PATH_BASE));
    define("HTTP_PATH_APP", HTTP_PATH_ROOT .
            str_replace(DS, US, RELATIVE_PATH_APP));
    define("HTTP_PATH_LIBRARY", false);
    define("HTTP_PATH_HELPERS", false);
    define("HTTP_PATH_TEMPLATE", false);
    define("HTTP_PATH_CONFIG", false);
    define("HTTP_PATH_PAGES", false);
    define("HTTP_PATH_ASSET", HTTP_PATH_ROOT .
            str_replace(DS, US, RELATIVE_PATH_ASSET));
    define("HTTP_PATH_ASSET_IMG", HTTP_PATH_ROOT .
            str_replace(DS, US, RELATIVE_PATH_ASSET_IMG));
    define("HTTP_PATH_ASSET_CSS", HTTP_PATH_ROOT .
            str_replace(DS, US, RELATIVE_PATH_ASSET_CSS));
    define("HTTP_PATH_ASSET_JS", HTTP_PATH_ROOT .
            str_replace(DS, US, RELATIVE_PATH_ASSET_JS));
}

// -----------------------------------------------------------------------
// DEFINE REQUEST PARAMETERS
// -----------------------------------------------------------------------
define("REQUEST_QUERY",
        isset($_SERVER["QUERY_STRING"]) && $_SERVER["QUERY_STRING"] != '' ?
        $_SERVER["QUERY_STRING"] : false);
define("REQUEST_METHOD",
        isset($_SERVER["REQUEST_METHOD"]) ?
        strtoupper($_SERVER["REQUEST_METHOD"]) : false);
define("REQUEST_STATUS",
        isset($_SERVER["REDIRECT_STATUS"]) ?
        $_SERVER["REDIRECT_STATUS"] : false);
define("REQUEST_PROTOCOL",
        isset($_SERVER["HTTP_ORIGIN"]) ?
        substr($_SERVER["HTTP_ORIGIN"], 0,
        strpos($_SERVER["HTTP_ORIGIN"], '://') + 3) : 'http://');
define("REQUEST_PATH",
        isset($_SERVER["REQUEST_URI"]) ?
        str_replace(RELATIVE_PATH_BASE, '',
        $_SERVER["REQUEST_URI"]) : '_UNKNOWN_');
define("REQUEST_PATH_STRIP_QUERY",
        REQUEST_QUERY ?
        str_replace('?' . REQUEST_QUERY, '', REQUEST_PATH) : REQUEST_PATH);

// -----------------------------------------------------------------------
// DEFINE SITE PARAMETERS
// -----------------------------------------------------------------------
define("PRODUCTION", false);
define("PAGE_PATH_DEFAULT", US . 'index');
define("PAGE_PATH",
        (REQUEST_PATH_STRIP_QUERY === US) ?
        PAGE_PATH_DEFAULT : REQUEST_PATH_STRIP_QUERY);

如果你将上述代码添加到你自己的项目中,在此时输出所有用户常量(可以使用get_defined_constants(true)实现)应该会得到类似于以下结果的输出:
array (
  'LOCAL_PATH_BOOTSTRAP' => '/var/www/libraries/backend/Data/examples',
  'URL_SEPARATOR' => '/',
  'DS' => '/',
  'PS' => ':',
  'US' => '/',
  'RELATIVE_PATH_ROOT' => '',
  'LOCAL_PATH_ROOT' => '/var/www',
  'HTTP_PATH_ROOT' => 'localhost:8888',
  'RELATIVE_PATH_BASE' => '/libraries/backend/Data/examples',
  'RELATIVE_PATH_APP' => '/libraries/backend/Data',
  'RELATIVE_PATH_LIBRARY' => '/libraries/backend/Data/vendor',
  'RELATIVE_PATH_HELPERS' => '/libraries/backend/Data/examples',
  'RELATIVE_PATH_TEMPLATE' => '/libraries/backend/Data/examples/templates',
  'RELATIVE_PATH_CONFIG' => '/libraries/backend/Data/examples/config',
  'RELATIVE_PATH_PAGES' => '/libraries/backend/Data/examples/pages',
  'RELATIVE_PATH_ASSET' => '/libraries/backend/Data/examples/assets',
  'RELATIVE_PATH_ASSET_IMG' => '/libraries/backend/Data/examples/assets/img',
  'RELATIVE_PATH_ASSET_CSS' => '/libraries/backend/Data/examples/assets/css',
  'RELATIVE_PATH_ASSET_JS' => '/libraries/backend/Data/examples/assets/js',
  'LOCAL_PATH_BASE' => '/var/www/libraries/backend/Data/examples',
  'LOCAL_PATH_APP' => '/var/www/libraries/backend/Data',
  'LOCAL_PATH_LIBRARY' => '/var/www/libraries/backend/Data/vendor',
  'LOCAL_PATH_HELPERS' => '/var/www/libraries/backend/Data/examples',
  'LOCAL_PATH_TEMPLATE' => '/var/www/libraries/backend/Data/examples/templates',
  'LOCAL_PATH_CONFIG' => '/var/www/libraries/backend/Data/examples/config',
  'LOCAL_PATH_PAGES' => '/var/www/libraries/backend/Data/examples/pages',
  'LOCAL_PATH_ASSET' => '/var/www/libraries/backend/Data/examples/assets',
  'LOCAL_PATH_ASSET_IMG' => '/var/www/libraries/backend/Data/examples/assets/img',
  'LOCAL_PATH_ASSET_CSS' => '/var/www/libraries/backend/Data/examples/assets/css',
  'LOCAL_PATH_ASSET_JS' => '/var/www/libraries/backend/Data/examples/assets/js',
  'HTTP_PATH_BASE' => 'localhost:8888/libraries/backend/Data/examples',
  'HTTP_PATH_APP' => 'localhost:8888/libraries/backend/Data',
  'HTTP_PATH_LIBRARY' => false,
  'HTTP_PATH_HELPERS' => false,
  'HTTP_PATH_TEMPLATE' => false,
  'HTTP_PATH_CONFIG' => false,
  'HTTP_PATH_PAGES' => false,
  'HTTP_PATH_ASSET' => 'localhost:8888/libraries/backend/Data/examples/assets',
  'HTTP_PATH_ASSET_IMG' => 'localhost:8888/libraries/backend/Data/examples/assets/img',
  'HTTP_PATH_ASSET_CSS' => 'localhost:8888/libraries/backend/Data/examples/assets/css',
  'HTTP_PATH_ASSET_JS' => 'localhost:8888/libraries/backend/Data/examples/assets/js',
  'REQUEST_QUERY' => false,
  'REQUEST_METHOD' => 'GET',
  'REQUEST_STATUS' => false,
  'REQUEST_PROTOCOL' => 'http://',
  'REQUEST_PATH' => '/',
  'REQUEST_PATH_STRIP_QUERY' => '/',
  'PRODUCTION' => false,
  'PAGE_PATH_DEFAULT' => '/index',
  'PAGE_PATH' => '/index',
)

这是令人惊叹的优雅。 - suchislife

0

当使用操作码缓存或大量的require/include语句时,绝对路径从性能角度来看更好(尽管只有在包含数百个文件时才会注意到,例如使用Zend/Symfony等框架时)。

使用相对路径时,操作码缓存和PHP必须每次计算出文件的realpath,然后才能确定它是否已经知道该文件以及是否需要再次加载它。PHP内部维护了一个文件到文件位置的哈希映射表,只要不必每次进行上述计算,它就非常快速。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接