Bootstrapping com PHP e Arquivo de Inicialização

Bootstrapping com PHP e Arquivo de Inicialização

 

Neste post vou lhe mostrar como fazer o bootstrapping (ou boot) de sua aplicação PHP. Vamos criar um arquivo de inicialização, que vai ser executado em todas as requisições. Isso vai garantir que a execução ocorra da forma correta, evitando erros.

Essa prática é muito importante pois ela garante integridade ao seu sistema. Seguindo esse modelo, é possível centralizar as configurações do sistema. Assim, sempre que precisar alterar uma configuração, basta fazer isso em um único arquivo, e ela se refletirá em toda a aplicação.

Mas o que é Bootstrapping, afinal?

A palavra bootstraping significa um processo de inicialização. É comum falarmos sobre boot do Sistema Operacional. Porém também podemos fazer bootstrap (ou boot) de nossas aplicações, sejam elas em PHP ou em outras linguagens. Vou mostrar um exemplo usando PHP, mas a lógica é a mesma para qualquer outra linguagem.

 

Estrutura da Aplicação

É necessário que todas as requisições à sua aplicação sejam processadas por um único arquivo (geralmente index.php), que, conforme a URL, chama outros scripts ou métodos.

Essa é a abordagem usada nas URLs Amigáveis ou nas Query Strings.

Caso você ainda não use esta técnica, recomendo ler este meu artigo.

Exemplo de Arquivo de Bootstrapping

Vamos criar um script (init.php), que faz basicamente duas coisas:

  1. Define configurações do PHP para toda a aplicação;
  2. Cria constantes que serão usadas na aplicação.

Um simples exemplo é o seguinte:

 

<?php 
 
/* =============================
   Configurações do PHP
   =========================== */
 
// define valores padrão para diretivas do php.ini
ini_set( 'error_reporting', -1 );
ini_set( 'display_errors', 0 ); // deve ser definida para zero (0) em ambiente de produção
 
// timezone
date_default_timezone_set( 'America/Sao_Paulo' );
 
 
// tempo máximo de execução de um script
set_time_limit( 60 );
 
 
 
/* ======================================
   Cria constantes usadas na aplicação
   =================================== */
 
// conexão com base de dados
define( 'BD_SERVIDOR', 'localhost' );
define( 'BD_USUARIO', 'usuario' );
define( 'BD_SENHA', 'senha' );
define( 'BD_NOME', 'nome_banco' );
 
// conexão SMTP
define( 'SMTP_SERVIDOR', 'mail.servidor.com.br' );
define( 'SMTP_USUARIO', 'usuario' );
define( 'SMTP_SENHA', 'senha' );

O exemplo é simples. Porém mostra a ideia geral do bootstrapping.

Salve o script como init.php. Dê um require_once nele em seu index.php. Dessa forma, todas as requisições vão passar pelo init.php, garantindo a integridade da aplicação.

Também é possível separar o init.php em arquivos menores. Por exemplo, um para configurações do PHP, outro para configurações de acesso a bancos de dados, outro para SMTP e assim por diante. Apenas lembre-se de dar um require_once em todos eles no init.php.

Melhorando o Script de Bootstrapping

Vamos melhorar o script de bootstrapping, fazendo duas alterações principais:

  1. Passar as configurações do PHP para outro arquivo;
  2. Usar um arquivo .ini para guardar as configurações de banco de dados, SMTP etc

Arquivos .ini são muito usados para configurações. E o melhor: o PHP pode manipular arquivos .ini nativamente.

Crie o arquivo php-config.php (ou outro nome que preferir) com o seguinte conteúdo:

<?php
 
// define valores padrão para diretivas do php.ini
ini_set( 'error_reporting', -1 );
ini_set( 'display_errors', 0 ); // deve ser definida para zero (0) em ambiente de produção
 
// timezone
date_default_timezone_set( 'America/Sao_Paulo' );
 
 
// tempo máximo de execução de um script
set_time_limit( 60 );

Nesse arquivo você poderá incluir outras configurações do PHP que forem necessárias para seu projeto.

Vamos também criar um arquivo chamado config.ini, com este conteúdo:

; Configurações de banco de dados
[db]
host = "localhost"
user = "usuario"
pass = "senha"
dbname = "nome_do_banco"

 
; Dados do SMTP
[smtp]
host = "smtp.servidor.com.br"
user = "usuario"
pass = "senha"

ATENÇÃO: O ideal é manter o config.ini fora da pasta pública (geralmente www ou public_html) do seu servidor. Assim não será possível acessar o arquivo pela URL e seus dados estarão seguros.

Precisaremos também de uma função para buscar os dados no arquivo ini. Para isso, vou usar a seguinte função:

function getConfig( $configName )
{
    $configFile = '../config.ini';
 
    $config = parse_ini_file( $configFile, true );
 
    list( $section, $param ) = explode( '.', $configName );
 
    if ( array_key_exists( $section, $config ) )
    {
        if ( array_key_exists( $param, $config[ $section ] ) )
        {
            return $config[ $section ][ $param ];
        }
    }
 
    return null;
}

A função recebe como parâmetro uma string no formato secao.configuracao e busca o valor correspondente no arquivo ini. Por exemplo, para buscar o valor do parâmetro host da seção db, basta executar getConfig( 'db.host' ).
Se o valor não existir, é retornado null

Para mais detalhes sobre como manipular arquivos ini com PHP, veja este post.

Nosso init.php ficará assim:

<?php
 
require_once 'php-config.php';
 
 
function getConfig( $configName )
{
    $configFile = '../config.ini';
 
    $config = parse_ini_file( $configFile, true );
 
    list( $section, $param ) = explode( '.', $configName );
 
    if ( array_key_exists( $section, $config ) )
    {
        if ( array_key_exists( $param, $config[ $section ] ) )
        {
            return $config[ $section ][ $param ];
        }
    }
 
    return null;
}

Otimização Usando Cache

Acesso a disco é uma tarefa muito lenta, que exige muito da CPU. O tempo de acesso a um dado em disco pode levar até 100.000 vezes mais tempo que um acesso à memória (veja o artigo The Pathologies of Big Data para mais detalhes). Esse número pode variar de diversas formas. Estou citando o pior caso.

É importante fazer cache da dados acessados frequentemente. Se você nunca trabalhou com cache em PHP, sugiro que leia este meu post, onde mostro como usar a biblioteca APC para fazer cache de dados.

Vou rescrever a função getConfig, usando cache. Usarei a técnica do “Carregamento Preguiçoso” (ou Lazy Load, em inglês), de forma que só vou carregar os dados no cache quando for necessário buscar uma informação pela primeira vez. Dessa forma, podemos economizar alguns milissegundos no carregamento da página, caso ela não precise, imediatamente, de algum dado do arquivo de configuração.

Vou incluir alguns dados de debug, para evidenciar a diferença no desempenho. Nosso arquivo index.php ficará assim:

<?php
require_once 'php-config.php';
 
// limpa o cache inicialmente, apenas para nosso teste de desempenho
apc_clear_cache();
 
function getConfig( $configName )
{
    // chave utilizada no APC para identificar o array $config no cache
    $apcConfigKey = 'app_config';
 
    // horário inicial, para nosso teste de desempenho
    $start = microtime( true );
 
    if ( ! apc_exists( $apcConfigKey ) )
    {
        echo "Buscando no arquivo...";
 
        $configFile = '../config.ini';
 
        $config = parse_ini_file( $configFile, true );
 
        // armazena em cache por 15 minutos (900 segundos)
        apc_store( $apcConfigKey, $config, 900 ); 
    }
    else
    {
        echo "Buscando no cache...";
 
        $config = apc_fetch( $apcConfigKey );
    }
 
    list( $section, $param ) = explode( '.', $configName );
 
    if ( array_key_exists( $section, $config ) )
    {
        if ( array_key_exists( $param, $config[ $section ] ) )
        {
            // tempo de execução total
            $time = microtime( true ) - $start;
            echo "Tempo total: " . number_format( $time, 20 );
 
            return $config[ $section ][ $param ];
        }
    }
 
    return null;
}
 
// Buscando dois dados, para comparar o tempo de acesso ao disco e ao cache
var_dump( getConfig( 'db.host' ) );
var_dump( getConfig( 'db.user' ) );

Se você executar o arquivo index.php, verá uma saída parecida com a seguinte:

Buscando no arquivo... 
Tempo total: 0.00008201599121093750
string 'localhost' (length=9)
 
Buscando no cache... 
Tempo total: 0.00001502037048339844
string 'usuario' (length=7)

Se dividirmos os tempo de execução, veremos que o tempo de acesso ao dado em cache é mais de 5 vezes menor.

Testes feitos, cache aprovado. Vamos retirar os trechos de teste de desempenho e de debug. Nosso index.php ficará desta forma, pronto para ser usado em produção:

<?php
require_once 'php-config.php';
 
function getConfig( $configName )
{
    $apcConfigKey = 'app_config';
 
    if ( ! apc_exists( $apcConfigKey ) )
    {
        $configFile = '../config.ini';
 
        $config = parse_ini_file( $configFile, true );
 
        // armazena em cache por 15 minutos (900 segundos)
        apc_store( $apcConfigKey, $config, 900 ); 
    }
    else
    {
        $config = apc_fetch( $apcConfigKey );
    }
 
 
    list( $section, $param ) = explode( '.', $configName );
 
    if ( array_key_exists( $section, $config ) )
    {
        if ( array_key_exists( $param, $config[ $section ] ) )
        {
            return $config[ $section ][ $param ];
        }
    }
 
    return null;
}

Dicas Avançadas

É possivel melhorar bastante esse arquivo de boostrapping, adicionando Autoload e Composer, por exemplo.

Não pretendo entrar em detalhes sobre isso, visto que este post tem o objetivo de mostrar algo simples, porém prático e útil.

Caso queira ver um exemplo mais completo, veja este link (em inglês), onde são usados Autoload e Composer no arquivo de Bootstrapping.

No Curso ULTIMATE PHP, no capítulo final, mostro passo-a-passo como montar uma aplicação utilizando, dentre outras técnicas, o conceito de Bootstrapping. Vou ensinar, em detalhes, como criar uma aplicação segura, estável e eficiente. Clique aqui para conhecer melhor o curso.

 

The following two tabs change content below.
Graduado em Ciência da Computação, pela Universidade Federal do Paraná (UFPR), é desenvolvedor de software desde 2008, com foco em Desenvolvimento Web com PHP.