O PHP inclui caminhos relativos ao arquivo ou ao código de chamada?

110

Estou tendo problemas para entender o conjunto de regras sobre os caminhos include relativos do PHP. Se eu executar o arquivo A.PHP- e o arquivo A.PHP incluir o arquivo B.PHP que inclui o arquivo C.PHP, o caminho relativo para C.PHP deve ser em relação à localização de B.PHP ou à localização de A .PHP? Isto é, importa de qual arquivo a inclusão é chamada ou apenas qual é o diretório de trabalho atual - e o que determina o diretório de trabalho atual?

Yarin
fonte
Mais precisa do que a resposta aceita em minha opinião: stackoverflow.com/a/23902890/1636522 .
folha de

Respostas:

132

É relativo ao script principal, neste caso A.php. Lembre-se de que include()apenas insere o código no script em execução no momento.

Ou seja, importa de qual arquivo a inclusão é chamada

Não.

Se você quiser fazer isso importar e incluir em relação a B.php, use a __FILE__constante (ou __DIR__desde o PHP 5.2 IIRC) que sempre apontará para o arquivo literal atual em que a linha de código está localizada.

include(dirname(__FILE__)."/C.PHP");
Pekka
fonte
@ Pekka- incrível- exatamente o que eu estava procurando. Para obter mais informações, consulte stackoverflow.com/questions/2184810/…
Yarin
7
Você também pode usar __DIR__para esse fim exato.
Nick Bedford
1
Esta resposta é um tanto exagerada: NÃO PRECISA include(dirname(__FILE__)."/C.PHP");, porque include("C.PHP");é o suficiente (Sim! C.PHP pode estar no mesmo diretório que B.PHP). Ele pode falhar apenas quando houver dois arquivos C.PHP em seu projeto.
Johnny Wong
Para deixar mais claro: é relativo a B.php e A.php se sem o prefixo "./" ou "../" no caminho de inclusão. Veja minha resposta abaixo.
Johnny Wong
21

@Pekka me trouxe lá, mas só quero compartilhar o que aprendi:

getcwd() retorna o diretório onde reside o arquivo que você iniciou a execução.

dirname(__FILE__) retorna o diretório do arquivo que contém o código em execução no momento.

Usando essas duas funções, você sempre pode construir um caminho de inclusão relativo ao que você precisa.

por exemplo, se b.php e c.php compartilham um diretório, b.php pode incluir c.php como:

include(dirname(__FILE__).'/c.php');

não importa de onde b.php foi chamado.

Na verdade, essa é a maneira preferida de estabelecer caminhos relativos, já que o código extra libera o PHP de ter que iterar por meio de include_path na tentativa de localizar o arquivo de destino.

Fontes:

Diferença entre getcwd () e dirname (__ FILE__)? Qual devo usar?

Por que você deve usar dirname (__ FILE__)

Yarin
fonte
Eu gostaria de adicionar algo, eu tinha um arquivo chamado csb.php, incluía um arquivo de funções de uma pasta, e o arquivo de funções incluía um arquivo chamado t.php da mesma pasta que o arquivo de funções, quando tentei incluir um arquivo chamado csb.php da pasta t.php estava, ele começou a incluir o mesmo csb.php que chamava o arquivo de funções, mas quando mudei o segundo csb.php para csbe.php ele começou a funcionar imediatamente. Portanto, parece que prioriza a primeira pasta, depois a segunda pasta de inclusão!
Miguel Vieira
17
  1. Se o caminho de inclusão não começar com ./ou ../, por exemplo:

    include 'C.php'; // precedence: include_path (which include '.' at first),
                     // then path of current `.php` file (i.e. `B.php`), then `.`.
    
  2. Se o caminho de inclusão começa com ./ou ../, por exemplo:

    include './C.php';  // relative to '.'
    
    include '../C.php'; // also relative to '.'
    

O .ou ..acima é relativo a getcwd(), cujo padrão é o caminho do .phparquivo de entrada (ou seja A.php).

Testado em PHP 5.4.3 (Data de compilação: 8 de maio de 2012 00:47:34).

(Observe também que chdir()pode alterar a saída de getcwd().)

Johnny Wong
fonte
Para concluir, o caminho de A.php é pesquisado primeiro por C.php, então o caminho de B.php é pesquisado se nenhum prefixo './' ou '../' no include. (Assume a configuração padrão do PHP)
Johnny Wong
Obrigado por me ajudar chdir(__DIR__)a resolver o problema.
HartleySan
[...] getcwd(), cujo padrão é o caminho do arquivo .php de entrada [...] - não necessariamente verdadeiro. Se eu executar o PHP na linha de comando, ele getcwd()se refere ao diretório de trabalho atual do shell, independentemente de qual .phparquivo eu invoco. Posso imaginar, porém, que se o PHP for executado em um ambiente de servidor da web, o ambiente inicializará o diretório de trabalho atual para o .phparquivo de entrada . Testado em macOS com PHP 7.2.2 instalado via Homebrew.
herzbube
16

A resposta aceita por Pekka é incompleta e, em um contexto geral, enganosa. Se o arquivo for fornecido como um caminho relativo, a construção de linguagem chamada includeo pesquisará da seguinte maneira.

Primeiro, ele percorrerá os caminhos da variável de ambiente include_path, que pode ser definida com ini_set. Se isso falhar, ele pesquisará no próprio diretório do script de chamada dirname(__FILE__)( __DIR__com php> = 5.3.) Se isso também falhar, só então ele pesquisará no diretório de trabalho! Acontece que, por padrão, a variável de ambiente include_pathcomeça com ., que é o diretório de trabalho atual. Essa é a única razão pela qual ele pesquisa primeiro no diretório de trabalho atual. Consulte http://php.net/manual/en/function.include.php .

Os arquivos são incluídos com base no caminho do arquivo fornecido ou, se nenhum for fornecido, o include_path especificado. Se o arquivo não for encontrado no include_path, o include irá finalmente verificar o próprio diretório do script de chamada e o diretório de trabalho atual antes de falhar.

Portanto, a resposta correta para a primeira parte da pergunta é que importa onde está localizado o script de chamada incluído. A resposta à última parte da pergunta é que o diretório de trabalho inicial , em um contexto de servidor web, é o diretório do script chamado, o script que inclui todos os outros enquanto é gerenciado pelo PHP. Em um contexto de linha de comando, o diretório de trabalho inicial é o que for quando o php é chamado no prompt, não necessariamente o diretório onde o script chamado está localizado. O diretório de trabalho atual , entretanto, pode ser alterado em tempo de execução com a função PHP chdir. Consulte http://php.net/manual/en/function.chdir.php .

Este parágrafo é adicionado para comentar sobre outras respostas. Alguns mencionaram que confiar em include_pathé menos robusto e, portanto, é preferível usar caminhos completos, como ./pathou __DIR__ . /path. Alguns chegaram a dizer que confiar no .próprio diretório de trabalho não é seguro, porque ele pode ser alterado. No entanto, algumas vezes, você precisa confiar nos valores do ambiente. Por exemplo, você pode desejar definir include_pathvazio, para que o diretório do script de chamada seja o primeiro lugar que ele pesquisará, mesmo antes do diretório de trabalho atual. O código pode já ter sido escrito e atualizado regularmente de fontes externas e você não deseja reinserir o prefixo __DIR__cada vez que o código for atualizado.


fonte
"se isso falhar, ele pesquisará no próprio diretório do script de chamada dirname(__FILE__) (__DIR__)com php> = 5.3.)" Tem certeza? Onde está documentado? Espero que você esteja errado e que o PHP não use __FILE__e __DIR__para esse propósito, já que isso interromperia imediatamente a inclusão de scripts "irmãos" de scripts com link simbólico ! : -o (Que, felizmente, parece funcionar bem aqui, na minha configuração 7.1.)
Sz.
6

Resposta curta: é relativo ao script de inclusão.

TFM explica isso corretamente:

Se o arquivo não for encontrado em include_path, include irá verificar no diretório do script de chamada e no diretório de trabalho atual

Portanto, se /app/main.php diz include("./inc.php")que localizará /app/inc.php .

O ./ não é estritamente necessário, mas remove qualquer dependência de include_path.

Eu não confiaria em encontrar arquivos de inclusão no diretório de trabalho atual para o caso de alguém alterá-lo com chdir().

Denis Howe
fonte
Portanto, se você iniciar a string com ./, ela verifica primeiro o diretório do script de chamada ou o diretório de trabalho atual?
Pacerier
2
@Denis Howe Não, você já está dependendo do diretório de trabalho atual se o caminho de inclusão começar com ./. ou seja, chdir ("/ app / other") fará include("./inc.php")falhar. Portanto, use include("inc.php")para estar seguro neste caso.
Johnny Wong
@Pacerier se a string começar com ./ ou ../, verifica apenas o diretório de trabalho atual. (include_path e diretório do script de chamada (B.php) são ambos ignorados). Veja minha resposta para mais detalhes.
Johnny Wong
-2
dir
-> a.php
-> c.php

- dir2 
-> b.php

Para incluir aem bque você precisainclude("../a.php");

Para incluir bem cque você precisainclude("dir2/b.php");

Olli
fonte
4
@ Olli- você está perdendo o ponto da questão - eu estava perguntando sobre como os caminhos relativos são determinados quando os includes são encadeados.
Yarin de