Projeto PHP do zero, vale a pena? – Série PHP sem framework

Vejo muitas dicussões por ai sobre a valia de se criar ou não um projeto PHP sem o uso de framework, mas existem muitas variáveis a serem consideradas na hora de decidir se vamos usar ou não um framework e qual será ele.

Para niverlarmos a conversa, vou definir PHP do zero com foco no contexto deste artigo, que seria criar um projeto sem usar nenhuma estrutura (framework) pronta. Eu já falei sobre o assunto em outro artigo, mas quero mudar um pouco “o clima” do artigo, vamos ver tudo por um âmbito mais prático.

Este artigo faz parte de uma série sobre organização de projetos PHP, se você quiser ser avisado sobre os próximos, assine a newsletter.

Um projeto PHP puro vale a pena?

Não quero ser repetitivo e explicar tudo o que eu já expliquei no artigo que mencionei acima, mas resumindo, tudo depende de um contexto maior em que o projeto PHP estará incluído.

Imagine que você está criando uma loja virtual e precisa integrar uma série de gateways de pagamento, nada melhor que criar um pacote separado do projeto principal onde teríamos uma interface em comum para os gateways e simplesmente alterar do PagSeguro para o PayPal com um parâmetro, além de ser bem legal e simples é completamente possível.

Agora que temos um contexto onde eu vou criar um pacote e este pacote não deixa de ser um projeto a ser realizado, não da pra usar um Laravel pra isso, não vale a pena usar o Slim Framework, não vale! Só o Composer já é o suficiente.

Eu não posso falar o mesmo sobre o resto da loja virtual, imagine criar toda uma loja sem um framework para auxiliar. É possível criar uma loja virtual sem frameworks? Sim! É viável? Provavelmente não.

Eu não tenha todas as variáveis para formular uma resposta definitiva, mas num geral, o tempo para se desenvolver com um framework será bem menor e esse é um grande ponto a favor, se não for o maior.

O que quero dizer aqui é que não da pra responder essa pergunta sem que exista um contexto, não adianta eu chegar pro cliente e dizer que o CakePHP é o melhor e ele dizer que quer o Zend Framework (e já aconteceu comigo) e não aceita outra coisa.

Regra de ouro: Conheça as ferramentas, escolha sua preferida, mas aprenda outras, na hora certa você vai saber o que escolher se tiver experiência suficiente, mas conhecimento em projeto PHP é válido para qualquer ferramenta escrita na linguagem.

O que eu preciso para criar um projeto sem framework?

Indo ao contrário de tudo o que me disseram e confiando na carga que adiquiri durante os anos, criar um projeto PHP sem framework exige MUITO mais experiência que um projeto COM framework, mas organização é o ponto chave que PODE até anular essa questão.

A primeira coisa que você precisa é definir as camadas que seu projeto terá. Para um projeto web eu gosto de usar a seguinte estrutura:

  • Middlewares
  • Rotas
  • MVC
  • Events e Listeners
  • Modularização (DDD é uma boa idéia, mas nem sempre)

Inclusive já falei sobre MVC e uma pequena introdução aos outros itens aqui no blog, para ler o artigo:

PHP e MVC – Tudo o que você precisa saber

Para evitar repetição, vou evitar falar sobre isso novamente, da uma olhada no artigo se tiver dúvidas.

Colocando a mão na massa – iniciando projeto PHP

Como disse no começo, quero que este artigo seja o mais prático, então vamos colocar a mão na massa e começar a criar um exemplo, que tal criarmos um site com CMS usando PHP puro, sem nenhum framework? Legal, né?

A primeira coisa que eu faço quando vou iniciar um projeto em que um framework não será usado é configurar o Composer, em especial o autoload das classes.

Se você não tem o Composer instalado ainda, veja este artigo.

Rode o comando composer init para começar a gerar um novo composer.json.

Algumas perguntas serão feitas, nesta ordem (aqui, já traduzidas):

  1. Nome do pacote (coloque seu nome ou username do GitHub e nome do pacote, separados por barra, tudo minusculo e com palavras separadas por hífen): erikfig/php-do-zero
  2. Descrição: Uma descrição para explicar o que projeto faz, eu deixei em branco (apenas teclei enter)
  3. Autor: Seu nome e seu email entre <>: Erik Figueiredo <erik.figueiredo@gmail.com>
  4. Licença: Descreve as permissões de uso, deixei em branco (apenas teclei enter)
  5. Você gostaria de definir suas dependências interativamente: Pacotes que o Composer vai instalar, você pode responder que não, teclar enter responderá sim, mas se teclar entender duas vezes vai pular a opção (eu acho mais rápido que escrever no).
  6. Você gostaria de definir suas dependências de desenvolvimento interativamente: a mesma coisa, mas para dependências que NÃO são necessárias para o projeto executar.
  7. Você confirma geração: Confirme (com enter) para criar o arquivo ou escreva no e tecle enter para cancelar.

Minhas respostas ficaram assim:

Resultado do comando composer init

E o arquivo final (você pode copiar e colar se não quiser rodar o composer init):

{
    "name": "erikfig/php-do-zero",
    "authors": [
        {
            "name": "Erik Figueiredo",
            "email": "erik.figueiredo@gmail.com"
        }
    ],
    "require": {}
}

E por fim vamos configurar o autoload, no meu caso eu quero carregar automaticamente todas as classes que estiverem no diretório src e pra isso acontecer eu preciso definir um namespace e dizer que ele se refere a este diretório (o src), o namespace que vou criar será chamado ErikFig\Framework.

Vamos configurar o composer.json com estas informações:

{
    "name": "erikfig/php-do-zero",
    "authors": [
        {
            "name": "Erik Figueiredo",
            "email": "erik.figueiredo@gmail.com"
        }
    ],
    "autoload": {
        "psr-4": {
            "ErikFig\\Framework\\": "src"
        }
    },
    "require": {}
}

Pronto, agora sempre que eu usar uma classe que esteja sob este namespace o arquivo será carregado automaticamente.

Claro que isso pode ficar um pouco confuso se você não conhece autoload ou namespaces, mas calma, continue lendo.

Por fim, vamos rodar o comando composer install para ele configurar tudo pra gente.

Vamos criar uma classe para testar? Dentro do diretório src crie um arquivo chamado Router.php, exatamente desta forma! Dentro dele adicione este conteúdo:

<?php

namespace ErikFig\Framework;

class Router
{
    public function handler()
    {
        return true;
    }
}

Note que além da classe eu adicionei um namespace, essa linha complementa o nome da classe de forma a torná-la única, podemos ter várias classes Router, cada uma sob um namespace, além disso o Composer usa este valor para fazer o require/include do arquivo automaticamente pra gente (o tal de autoload).

Veja na prática, crie um arquivo chamado bootstrap.php com o seguinte conteúdo:

<?php

// Carrego o arquivo do Composer que faz o autoload
require __DIR__ . '/vendor/autoload.php';

// Sem eu precisar fazer mais nada, TODOS os
// arquivos de rota serão incluídos automaticamente
$router = new ErikFig\Framework\Router;

Eu comentei o arquivo para facilitar o entendimento.

Mas claro que isso é só o começo, eu acabei de criar minha estrutura inicial, o próximo passo seria terminar minha classe Router, mas antes disso eu vou precisar de uma forma eficiente de ir testando tudo o que ela poderá fazer.

Eu sei que muita gente nem sabe o que a classe Router vai fazer, mas ok, vou falar disso na hora certa, no próximo artigo desta série.

Testando arquivos do projeto de forma eficiente

Muitos dizem que a melhor forma de testar um projeto é com TDD, mas não vou entrar no mérito sobre isso agora, o assunto sozinho da um artigo inteiro e além, deixarei um link a seguir que pode ajudar.

TDD na Wikipedia – https://pt.wikipedia.org/wiki/Test_Driven_Development

Aqui eu vou usar testes automatizados, sem TDD, então o importante para quem já conhece o assunto é se sentir confortável que TDD é uma prática, testes automatizados é uma ferramenta, não são a mesma coisa.

Para você que não conhece nada sobre TDD ou Testes Automatizados, teste automatizado é uma forma de testar o projeto escrevendo comportamentos que serão executados automaticamente, verificando se o resultado foi o esperado.

Entre outras palavras, é o que você já faz rodando um arquivo no navegador, mas aqui vamos fazer de forma totalmente transparente, rápida e com a possibilidade de repetir incansávelmente com apenas um comando.

Para começar, vamos instalar um framework de testes automatizados (olha! vou usar um framework! rsrs), rode o comando composer require phpunit/phpunit na raiz do projeto (mesmo diretório do composer.json).

Na sequência crie um arquivo chamado phpunit.xml com o conteúdo a seguir.

<phpunit
        bootstrap="vendor/autoload.php"
        colors="true">
    <testsuites>
        <testsuite name="Testes">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

Com esse arquivo eu digo ao PHPUnit que ele deve usar o autoload do Composer e que os arquivos de teste estão dentro do diretório tests.

Então crie um diretório chamado tests e dentro dele um RouterTest.php com o conteúdo a seguir.

<?php

namespace ErikFig\Framework;

use PHPUnit\Framework\TestCase;

class RouterTest extends TestCase
{
    /**
     * Com PHPUnit toda classe precisa terminar com Test,
     * como por exemplo, RouterTest.
     * 
     * Todo método de teste precisa iniciar com test e
     * descrever o que ele está testando, como 
     * testEsseMetodoDescreveOQueDeveAcontecer()
     *
     * @return void
     */
    public function testEsseMetodoDescreveOQueDeveAcontecer()
    {
        // o valor que eu quero testar
        $actual = (new Router)->handler();
        $expected = true; // o valor que eu espero

        /**
         * O método assertEquals é provido pela classe TestCase
         * que a RouterTest (esta que estamos) está herdando
         * ele verifica se o valor esperado (expected) é igual
         * ao valor atual (actual);
         */
        $this->assertEquals($expected, $actual);
    }
}

Note que eu documentei o arquivo para facilitar o entendimento.

Agora que já temos um ambiente de teste e até um arquivo de teste, vamos executar com o comando vendor/bin/phpunit.

O resultado é um sucesso, já que o valor atual é igual ao esperado.

PHPUnity retornando um sucesso

Agora se por algum motivo o resultado não for o esperado devemos ver isso claramente no formato de erro e em vermelho, tente trocar o retorno do método handler da classe Router para false e rode o comando vendor/bin/phpunit de novo.

<?php

namespace ErikFig\Framework;

class Router
{
    public function handler()
    {
        return false; // aqui
    }
}
PHPUnity retornando uma falha

O resultado é uma falha, já que esperavamos true e tinhamos um false.

Conclusão

Agora que temos um esqueleto de desenvolvimento propício, na próxima aula vamos aprender o que é um sistema de rotas e criar o nosso próprio.

Este artigo faz parte de uma série sobre organização de projetos PHP, se você quiser ser avisado sobre os próximos, assine a newsletter.

Autor: erik.figueiredo@gmail.com

Músico, gamer amador, tutor de programação, desenvolvedor freelancer full cycle, com foco em PHP (Laravel e CakePHP), Javascript (Front e Node.js), Dart (Front e Flutter) e infra.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *