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:
- Define configurações do PHP para toda a aplicação;
- 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' ); </pre> <p>O exemplo é simples. Porém mostra a ideia geral do <em>bootstrapping</em>.</p> <p>Salve o script como <code>init.php</code>. Dê um <code>require_once</code> nele em seu <code>index.php</code>. Dessa forma, todas as requisições vão passar pelo init.php, garantindo a integridade da aplicação.</p> <p>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 <code>require_once</code> em todos eles no init.php.</p> <h2>Melhorando o Script de <em>Bootstrapping</em></h2> <p>Vamos melhorar o script de <em>bootstrapping</em>, fazendo duas alterações principais:</p> <ol> <li>Passar as configurações do PHP para outro arquivo;</li> <li>Usar um arquivo <code>.ini</code> para guardar as configurações de banco de dados, SMTP etc</li> </ol> <p>Arquivos <code>.ini</code> são muito usados para configurações. E o melhor: <a title="Arquivos .ini: processando arquivos de configuração com PHP" href="http://rberaldo.com.br/arquivos-ini-processando-arquivos-de-configuracao-com-php">o PHP pode manipular arquivos <code>.ini</code> nativamente</a>.</p> <p>Crie o arquivo <code>php-config.php</code> (ou outro nome que preferir) com o seguinte conteúdo:</p> <pre lang="php"> <?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 ); </pre> <p>Nesse arquivo você poderá incluir outras configurações do PHP que forem necessárias para seu projeto.</p> <p>Vamos também criar um arquivo chamado <code>config.ini</code>, com este conteúdo:</p> <pre lang="ini">; 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" </pre> <p><strong style="color: red;">ATENÇÃO</strong>: O ideal é manter o <code>config.ini</code> fora da pasta pública (geralmente <code>www</code> ou <code>public_html</code>) do seu servidor. Assim não será possível acessar o arquivo pela URL e seus dados estarão seguros.</p> <p>Precisaremos também de uma função para buscar os dados no arquivo ini. Para isso, vou usar a seguinte função:</p> <pre lang="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; } </pre> <p>A função recebe como parâmetro uma string no formato <code>secao.configuracao</code> e busca o valor correspondente no arquivo ini. Por exemplo, para buscar o valor do parâmetro <code>host</code> da seção <code>db</code>, basta executar <code>getConfig( 'db.host' )</code>.<br ?--> Se o valor não existir, é retornado <code>null</code> |
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.
Roberto Beraldo
Latest posts by Roberto Beraldo (see all)
- Não Tenha Preguiça de Ler! - 25/04/2016
- Como Atualizar Scripts PHP de MySQL Para MySQLi - 29/10/2015
- Como usar PDO com banco de dados MySQL - 10/09/2015