Проверьте, существует ли включение (или требование)

Как вы проверяете, существует ли include/require_once, прежде чем вы его вызовете, я пытался поместить его в блок ошибок, но PHP это не понравилось.

Я думаю, что file_exists() будет работать с некоторыми усилиями, однако для этого потребуется весь путь к файлу, и относительное включение не может быть легко передано в него.

Есть ли другие способы?


person MintDeparture    schedule 12.02.2010    source источник
comment
Можете ли вы показать нам код? Вы можете в основном объяснить, что вы пытаетесь сделать?   -  person JPro    schedule 12.02.2010
comment
@GZipp: Всем, кто предлагает использовать file_exists(): проверяет, существует ли файл или каталог. is_file() больше подходит в данном случае.   -  person Alix Axel    schedule 12.02.2010
comment
@Alix Axel: Всем, кто обращается ко мне: я не предлагал ничего, кроме того, что предположение Смики (о том, что относительный путь не может быть легко преобразован в полный путь) было неверным. Другие указали, что полный путь не нужен; следовательно, мой комментарий, а не ответ.   -  person GZipp    schedule 12.02.2010
comment
@Alix: is_file() лучше, чем file_exists(), но не лучше ли использовать is_readable()?   -  person AgentConundrum    schedule 24.11.2010
comment
@AgentConundrum: is_readable(): возвращает TRUE, если файл или каталог, указанный в имени файла, существует и доступен для чтения, в противном случае FALSE.   -  person Alix Axel    schedule 24.11.2010


Ответы (6)


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

if(!@include("script.php")) throw new Exception("Failed to include 'script.php'");

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

person Johannes Gorset    schedule 12.02.2010
comment
Вам не нужны круглые скобки вокруг значения аргумента include. include — это не функция, а языковая конструкция, подобная echo. - person Gumbo; 12.02.2010
comment
@Gumbo Я считаю хорошей практикой использовать круглые скобки для языковых конструкций, как я делаю с echo() и print(). - person Johannes Gorset; 12.02.2010
comment
Я не уверен, что это хорошее решение: вы не увидите фатальных ошибок. - person Michał Maluga; 23.08.2011
comment
@Michal Malunga: я не уверен, что вы понимаете вопрос. - person Johannes Gorset; 24.08.2011
comment
если вы получаете сообщение об ошибке не может повторно объявить... при удалении символа @ перед include, попробуйте вместо него include_once. - person nerdess; 08.01.2012
comment
@Johannes Gorset: Михал указал на очень серьезную проблему. Я использую описанный выше подход (с отключенным оператором) и для механизма JSON RPC. А иногда сценарии завершаются сбоем без ЛЮБОЙ ошибки в лог-файле. Линтинг ваших скриптов гарантирует, что они не завершатся сбоем из-за (приглушенной) синтаксической ошибки. Однако некоторые проблемы можно обнаружить только во время выполнения, например, класс, который пытается переопределить открытый конструктор родителя закрытым. Очень легко исправить и посмотреть, ЕСЛИ вы не забыли удалить оператор отключения звука для отладки. - person Shi; 11.08.2012
comment
Лучше использовать include_once или require_once , это будет полезно при использовании OOP Concept и позволит избежать повторного объявления классов. - person Rafee; 23.08.2012
comment
@Shi Это правда, если кто-то использует это, ему нужно быть осторожным. Я бы сказал, однако, что в некоторых ситуациях это может быть полезно. Моя ситуация заключается в том, что если конкретное include_once не происходит, класс отсутствует, поэтому нам нужно больше действий, чем файл журнала. Если корректирующие меры не работают, мы отправляем сообщение администратору через его учетную запись внешнего пользователя. Мы также продолжаем и выдаем настоящую ошибку, если класс отсутствует по require_once сразу после исправления. - person Garet Claborn; 22.09.2013

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

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

OR

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

OR

if (class_exists('class_name')) { /*code*/ }
person Khawar    schedule 29.05.2012
comment
проблема тут в том, что если включение не сработает в первую очередь - выдаст и ошибку/предупреждение.. - person Obmerk Kronen; 25.02.2014

Обратите внимание на функцию stream_resolve_include_path, она выполняет поиск по тем же правилам, что и include().

http://php.net/manual/en/function.stream-resolve-include-path.php

person Stephane JAIS    schedule 29.10.2012
comment
Несколько пользовательских заметок здесь: кажется, что stream_resolve_include_path() кэширует свой вывод. После того, как я переименовал файл, мне пришлось перезапустить Apache, чтобы функция stream_resolve_include_path() не возвращала несуществующее имя файла. Это было на винде. Он действительно ведет себя как include и разрешает имя файла только по пути включения, если путь относительный. В любом случае нет особого смысла разрешать уже абсолютные пути. - person RationalRabbit; 07.05.2019

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;
}
person Yacoby    schedule 12.02.2010
comment
file_exists не может выполнять поиск по включенным путям. Вам придется разбирать их вручную. - person Petr Peller; 12.02.2010
comment
PS == PATH_SEPARATOR && DS == DIRECTORY_SEPARATOR для тех, кому интересно, +1, надеюсь, вы это исправите, это прекрасно работает и без дополнительных затрат на обработку исключений и ошибок - person mschr; 16.07.2012

file_exists() работает с относительными путями, а также проверяет, существуют ли каталоги. Вместо этого используйте is_file():

if (is_file('./path/to/your/file.php'))
{
    require_once('./path/to/your/file.php');
}
person Alix Axel    schedule 12.02.2010
comment
Хотя он работает с относительными путями, он не работает с путями включения - на что следует обратить внимание;) - person Billy ONeal; 12.02.2010

Я думаю, что правильный способ сделать это:

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

Это связано с тем, что документация говорит, что stream_resolve_include_path разрешает "имя файла по пути включения в соответствии с теми же правилами, что и fopen()/include".

Некоторые люди предлагали использовать is_file или is_readable, но это не для общего случая использования, потому что в общем случае, если файл заблокирован или недоступен по какой-либо причине после того, как file_exists возвращает TRUE, это то, что вы нужно заметить с очень уродливым сообщением об ошибке прямо на лице конечного пользователя, иначе вы будете открыты для неожиданного и необъяснимого поведения позже с возможной потерей данных и тому подобными вещами.

person jacmkno    schedule 26.04.2017