检查是否存在一个包含文件(include)或者需求文件(require)

52

如何在调用 include/require_once 之前检查其是否存在?我尝试将它放在错误块中,但 PHP 不喜欢这样做。

我认为使用 file_exists() 可以解决问题,但这需要整个文件路径,并且相对路径不容易传递给它。

还有其他的方法吗?


答案:在 PHP 中可以使用函数 function_exists() 来检查一个函数是否已经定义。如果你想检查一个文件是否已经包含,可以使用 get_included_files() 函数来获取所有已经包含的文件列表。然后你可以使用 in_array() 函数来检查你要包含的文件是否已经在列表中。

1
你能展示一些代码吗?你能基本解释一下你想做什么吗? - JPro
3
对于那些建议使用file_exists()的人:这个函数检查文件或目录是否存在。在这种情况下,更适合使用is_file() - Alix Axel
1
@Alix Axel:对于所有在@我 的人:我并没有提出建议,只是想说Smickie的假设(相对路径无法轻松地转换为完整路径)是错误的。其他人已经指出完整路径是不必要的;因此我只是评论而不是回答。 - GZipp
@Alix:is_file() file_exists() 好,但使用 is_readable() 不是更好吗? - AgentConundrum
1
@AgentConundrum: is_readable(): "如果由文件名指定的文件或目录存在且可读,则返回TRUE,否则返回FALSE"。 - Alix Axel
6个回答

61

我相信file_exists函数可以使用相对路径,不过你也可以尝试类似以下的代码...

if(!@include("script.php")) throw new Exception("无法包含 'script.php' 文件");

需要注意的是,你可以将抛出异常的部分替换为任何你喜欢的错误处理方法。这里的想法是,if语句验证文件是否可以被包含,通过在其前面加上@符号来压制include通常输出的任何错误消息。


2
你不需要在include的参数值周围加上括号。include不是一个函数,而是像echo一样的语言结构。 - Gumbo
7
我认为在语言结构中使用括号是一个很好的习惯,就像我对 echo()print() 做的那样。 - Johannes Gorset
2
我不确定这是否是一个好的解决方案:您将看不到致命错误。 - Michał Maluga
1
@Michal Malunga:我不确定你是否理解这个问题。 - Johannes Gorset
3
在使用面向对象编程概念时,最好使用 include_oncerequire_once,这有助于避免重新声明类的问题。 - Rafee
显示剩余3条评论

12

这里有几个用户贡献的注释:stream_resolve_include_path() 似乎会缓存其输出。在我重命名文件后,我必须重新启动 Apache 才能使 stream_resolve_include_path() 不返回不存在的文件名。这是在 Windows 上发生的。 它的行为确实像 include,只有在路径是相对路径时,才会根据包含路径解析文件名。已经是绝对路径名的解析并没有太多意义。 - RationalRabbit

9

您还可以检查包含文件中定义的任何变量、函数或类,并查看是否已成功包含。

if (isset($variable)) { /*code*/ }

或者

if (function_exists('function_name')) { /*code*/ }

或者

if (class_exists('class_name')) { /*code*/ }

问题在于,如果包含文件一开始就无法工作 - 它会抛出错误/警告.. - Obmerk Kronen

7

file_exists()函数可以使用相对路径,并且它还会检查目录是否存在。但是建议使用is_file()函数代替它:

if (is_file('./path/to/your/file.php'))
{
    require_once('./path/to/your/file.php');
}

虽然它可以使用相对路径,但无法使用包含路径 - 这是需要注意的 ;) - Billy ONeal

6

file_exists函数可以用于检查相对于当前工作目录的所需文件是否存在,因为它可以很好地处理相对路径。但是,如果包含文件在PATH中的其他位置,则必须检查多个路径。

function include_exists ($fileName){
    if (realpath($fileName) == $fileName) {
        return is_file($fileName);
    }
    if ( is_file($fileName) ){
        return true;
    }

    $paths = explode(PS, get_include_path());
    foreach ($paths as $path) {
        $rp = substr($path, -1) == DS ? $path.$fileName : $path.DS.$fileName;
        if ( is_file($rp) ) {
            return true;
        }
    }
    return false;
}

1
file_exists函数不能在包含路径中搜索。您必须手动解析它们。 - Petr Peller
1
对于那些想知道的人,PS == PATH_SEPARATOR && DS == DIRECTORY_SEPARATOR。希望你能修复它,这样做非常好,而且没有异常和错误处理的开销。 - mschr

2
我认为正确的方法是这样做:

if(file_exists(stream_resolve_include_path($filepath))){
  include $filepath;    
}

这是因为文档中指出,stream_resolve_include_path会根据与fopen()/include相同的规则将"文件名与包含路径相匹配"。

一些人建议使用is_fileis_readable,但这不适用于一般情况,因为在一般情况下,如果文件在file_exists返回TRUE后被阻止或不可用,那么您需要在最终用户面前通过一个非常丑陋的错误消息来通知他们,否则您将面临意外和无法解释的行为,可能会导致数据丢失等问题。

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