PHP para Iniciantes: Estruturas de Controle - INCLUDE, REQUIRE, INCLUDE_ONCE e REQUIRE_ONCE

Ok, eu falei que o artigo de hoje seria sobre require, mas não que seria somente isso, hehe. Eu decidi de última hora falar de todas as variações de inclusão de arquivo pois suas operações são bem semelhantes, pra não dizer praticamente iguais. A ação do código é exatamente a mesma, as diferenças estão na semântica. Então por que não começarmos refletindo sobre isso, como de costume?

Reflexão sobre semântica

Include significa incluir em inglês e sua ação é sempre voltada a outro arquivo. Com isso podemos entender que sua proposta semântica é INCLUA (arquivo), simples assim.

require, significa necessitar, o que remete ao cenário de que seu script precisa de outro arquivo para funcionar corretamente. Nesse caso, já podemos ver um certo acúmulo de responsabilidades... Pois necessitar e incluir são verbos distintos, mas no PHP, ambos são executados no require.

Kiko, eu ainda não concordo com o acúmulo... Não ficou muito claro.

É simples. Quando você escreve require "arquivo.php", o que você lê, semanticamente falando? REQUER "arquivo.php". Beleza, você falar ao interpretador que REQUER (algo), dá a entender que basta verificar se esse arquivo já foi incluído alguma vez, não? Porém, o que o require faz é acionar o include e, se o arquivo não existir, dispara um erro de compilação ( E_COMPILE_ERROR), encerrando a interpretação do código.

Ou seja, a semântica literal acaba sendo INCLUA OBRIGATORIAMENTE (arquivo). O nome poderia ser algo do tipo include_required(), entende? Por isso eu penso que o nome por si só não foi a melhor das melhores escolhas... E tudo bem! O que importa é que você vai lembrar pra que serve o require. Além disso, essa chamada existe em outras linguagens dessa mesma forma, portanto, não é tão estranha assim no mundo da programação.

Na prática

Ao contrário do que costumarmos pensar, o arquivo incluído com include ou require não precisa ser um script PHP. Porém, como nosso interpretador só consegue entender PHP, se você colocar qualquer outro tipo de arquivo, ele só vai pegar seu conteúdo e jogar no buffer de saída da requisição.

Tá, mas por que alguém iria incluir outra coisa, Kiko?

Ora, para fazer tratamentos ou atalhos! Eu mesmo já fiz um script para capturar dinamicamente imagens de um bucket S3 da Amazon, salvar na cache da aplicação e abrir ali mesmo. Então os usuários, ao invés de abrir diretamente a imagem no servidor de hospedagem, acessavam uma cache temporária criada na aplicação via script PHP. Mas eu não fiz isso com include, e sim com a função file_get_contents().

Ué, por quê, Kiko?

Pois tem muita diferença na semântica e nas consequências. As estruturas include e require fazem com que o interpretador tente interpretar o arquivo incluído. Isso significa que, se por algum motivo, existir alguma tag de abertura de interpretação (<?php ou <?), o PHP vai tentar interpretar e provavelmente não vai ser nada legal.

Por isso, se você está tentando incluir os dados de um arquivo onde você notoriamente sabe que seu conteúdo não é nada em PHP, há funções mais seguras e que podem até melhorar a semântica no seu fluxo.

$bin = file_get_contents('image.png'); é bem mais claro, não é?

Ainda assim, funciona para outros arquivos sim. Ah, e também funciona para links!

Quê?!

Sim, é possível incluir scripts externos à sua aplicação, mas, nesse caso, as estruturas só funcionam para scripts PHP. Qualquer outro formato resultará em erro.

Configurações

Sobre tudo isso que mencionei acima, tem alguns pontos importantes de mencionar sobre a configuração do PHP. Para que cada caso funcione, você precisa se ligar nessas duas palavrinhas:

  • include_path: se você não quiser ficar escrevendo o diretório e todos os arquivos que você quer incluir ficam na mesma pasta, você pode inserir o caminho absoluto dessa pasta nessa configuração. Assim, se você definir include_path=/var/inc/, quando você fizer include('arquivo.php'), o interpretador tentará incluir o arquivo /var/inc/arquivo.php. Se essa configuração não for preenchida, a inclusão de arquivos sem diretórios será feita a partir da pasta do escopo do script. Nesse caso, se o arquivo está em /var/www, aquele include tentaria incluir o arquivo /var/www/arquivo.php. Não existe um require_path, porque esse aqui também afeta o require. Se você quiser usar o caminho relativo quando tiver preenchido essa configuração, basta colocar a notação de diretório relativo './', ficando include('./arquivo.php'). Também é possível usar a notação de "diretório-pai" '../';
  • allow_url_include: se você deseja incluir links, essa configuração precisa ser true. Não é recomendado, então nem conte com isso. Se ainda assim quiser ativar, verifique os protocolos suportados pelo PHP listados na documentação oficial.

Retorno

Assim como mencionado no artigo anterior, se o script incluído encerrar sua chamada com a estrutura return, o retorno da inclusão será o que for passado aqui. Porém, se nada for retornado, então teremos duas situações na estrutura include:

  • 1, se conseguiu incluir;
  • false, se não, emitindo um erro de alerta (E_WARNING).

No caso do require, se não conseguir incluir, o interpretador emitirá o erro de compilação que mencionei mais cedo, então nem faz sentido ele ter algum retorno condicionado, não é?

Sintaxe

Ok, falei, falei, falei... E não mostrei nada. Bem, só tem duas sintaxes possíveis:

1 - Como uma função (com parênteses)

  • include('arquivo')
  • require('arquivo')

2 - Como um operador, sem parênteses

  • include 'arquivo'
  • require 'arquivo'

Nenhuma das duas formas é abominada no mercado. O importante aqui é você sempre manter o padrão do projeto: se usa um, continue usando dessa forma!

Exemplos

Agora vamos trabalhar em cases!

Vamos supor que você está montando um formulário e que, no final do processo, você deseja incluir a assinatura do chefe. Essa assinatura está estruturada no arquivo includes/assinatura.php e você não precisa mexer nela, sendo o HTML retornado pelo script via estrutura return ao invés de ser impresso no buffer. Como fica esse arquivo?

<?php
$html = '<!DOCTYPE html><html><head></head><body>';
// ... código mágico aqui, onde geramos o HTML
$html .= include('./includes/assinatura.php');
$html .= '</body></html>';
// pronto, html concluído.

Ah, Kiko, e se o arquivo fosse includes/assinatura.html?

Nesse caso, o ideal não seria usar o include, mas ainda seria possível com as funções de manipulação de buffer ob_start() e ob_get_clean():

<?php
$html = '<!DOCTYPE html><html><head></head><body>';
// ... código mágico aqui, onde geramos o HTML
ob_start(); // inicia a captura de buffer da requisição
include('./includes/assinatura.html'); // joga todo o HTML no buffer
$html .= ob_get_clean(); // seta o que capturou em $html e remove do buffer
$html .= '</body></html>';
// pronto, html concluído.

E se houver a chance do HTML não existir, Kiko?

Aí é onde podemos aplicar o require:

<?php
$html = '<!DOCTYPE html><html><head></head><body>';
// ... código mágico aqui, onde geramos o HTML
ob_start(); // inicia a captura de buffer da requisição
require('./includes/assinatura.html'); // joga todo o HTML no buffer
$html .= ob_get_clean(); // seta o que capturou em $html e remove do buffer
$html .= '</body></html>';
// pronto, html concluído.

Inclusões únicas

Além das estruturas include e require, também é possível encontrar as variantes _once (include_once e require_once). O papel aqui é atribuir mais um dever à estrutura: o de verificar se é a primeira vez que o arquivo ou link está sendo incluído pelo interpretador.

Isso serve para evitar recursões infinitas ou evitar que um código seja incluído mais de uma vez na mesma requisição (o que caracteriza certa falta de controle sobre o código).

Por exemplo, em códigos mais antigos, é comum encontrar um arquivo exclusivo de conexão ao banco de dados. Quando você encontra projetos assim, você já pode imaginar que a variável de conexão representa uma variável global. Porém, a pessoa que escreve esse tipo de código não quer correr o risco de ficar reescrevendo a conexão toda hora... O que ela faz?

Bom, em todo fluxo que precisa ter conexão com o código, ela chama a estrutura include_once. Se o script nunca foi incluído, então será interpretado e inicializará a conexão pela primeira vez. Mas se já foi, então a instrução será ignorada.

Funciona da mesma forma no require_once: ah, o banco é obrigatório, se o arquivo não existir então precisamos parar a execução daquele código. Então ao invés de include_once, o require_once será escolhido.

Nota: apesar de eu não aprovar códigos escritos assim, eu não estou repudiando essas ações! Códigos escritos dessa forma são evidências de que o desenvolvedor está tentando organizar alguma coisa, no final das contas, e evitando repetição de código. Então está menos mal. Não se sinta ruim se já fez códigos assim, beleza? Mas vamos melhorar, por favor!

E por hoje é só! Curtiu? Comenta e compartilha! Você já conhecia o include e require? Fala aí pra eu ver uma coisa, rs. No próximo artigo, falarei sobre a última estrutura de controle: GOTO. Quem já mexeu com linguagem antiga já vai sacar... Mas não deixe de ler, hein?

Inté!!