jonatasrt / template
Template engine PHP 8+ sem código PHP no HTML: variáveis, blocos, objetos e modificadores. Compatível com a sintaxe do raelgc/template.
Requires
- php: >=8.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Engine de template para PHP 8.0+ que mantém o HTML completamente livre de código PHP.
Esta biblioteca é uma reescrita moderna da clássica raelgc/template (criada por Rael Gugelmin Cunha), com compatibilidade total de sintaxe: as mesmas variáveis, os mesmos blocos, os mesmos modificadores, o mesmo suporte a objetos e comentários.
Você não precisa reescrever nenhum arquivo HTML. Qualquer template que funcionava na versão antiga funciona aqui, sem nenhuma alteração.
Índice
- Requisitos
- Instalação
- Migrando do raelgc/template
- Olá Mundo
- Variáveis
- Checando se variáveis existem
- Variáveis dinâmicas
- Variáveis com modificadores
- Blocos
- Blocos aninhados
- Blocos automáticos por padrão
- Blocos FINALLY
- Blocos com HTML select
- Usando vários arquivos HTML
- Guardando o conteúdo do template
- Usando objetos
- Comentários
- Escapando variáveis
- Criando XML, CSV e outros formatos
- Mensagens de erro
- Precisão e desempenho
- Referência da API
- Licença
Requisitos
- PHP >= 8.0 (testado em 8.0, 8.1, 8.2, 8.3 e 8.4)
- Nenhuma extensão além das padrão (
pcre,json)
Não há warnings, notices nem deprecations mesmo com error_reporting(E_ALL).
Instalação
Via Composer
composer require jonatasrt/template
<?php require_once("vendor/autoload.php"); use jonatasrt\view\Template;
Via download / cópia manual
Baixe o repositório e inclua o arquivo diretamente:
<?php require_once("lib/jonatasrt/view/Template.php"); use jonatasrt\view\Template;
Migrando do raelgc/template
O HTML não muda em nada. No PHP, só existem duas possibilidades:
Opção 1 — trocar o use (recomendado):
// antes use raelgc\view\Template; // depois use jonatasrt\view\Template;
Opção 2 — nem mexer no use: crie um alias logo depois de carregar a biblioteca e todo o
código antigo continua funcionando sem nenhuma alteração:
require_once("vendor/autoload.php"); class_alias('jonatasrt\view\Template', 'raelgc\view\Template');
A partir daí, use raelgc\view\Template; e new raelgc\view\Template(...) seguem válidos.
Se por algum motivo a versão antiga ainda estiver carregada no mesmo processo, não há conflito: a função global
replace()é declarada dentro de umfunction_exists().
Olá Mundo
hello.html:
<html> <body> Olá {FULANO}! </body> </html>
hello.php:
<?php require_once("vendor/autoload.php"); use jonatasrt\view\Template; $tpl = new Template("hello.html"); $tpl->FULANO = "Mundo"; $tpl->show();
Resultado:
<html> <body> Olá Mundo! </body> </html>
Variáveis
Toda variável de template é escrita entre chaves: {NOME_DA_VARIAVEL}.
- São aceitos apenas caracteres alfanuméricos e o underscore (
_). - São case sensitive:
{FULANO}é diferente de{fulano}. - São identificadas automaticamente na leitura do arquivo — não é preciso declarar nada.
- Variáveis não preenchidas são removidas do resultado final (não sobra
{VARIAVEL}na tela).
$tpl->NOME = "Maria"; $tpl->IDADE = 32; // int, float e bool são convertidos automaticamente $tpl->NADA = null; // vira string vazia $tpl->TAGS = ['a','b']; // arrays viram "a, b"
Atribuir uma variável que não existe no HTML lança uma exceção:
$tpl->INEXISTENTE = "x"; // RuntimeException: var INEXISTENTE does not exist
Esse comportamento é intencional: ele avisa cedo sobre erros de digitação.
Checando se variáveis existem
if ($tpl->exists("FULANO")) { $tpl->FULANO = "Maria"; } // isset() também funciona if (isset($tpl->FULANO)) { $tpl->FULANO = "Maria"; }
Variáveis dinâmicas
Quando o nome da variável só é conhecido em tempo de execução, use chaves:
$varname = "fulano"; $tpl->{"NOME_" . strtoupper($varname)} = "Maria"; // preenche {NOME_FULANO}
Variáveis com modificadores
É possível aplicar funções PHP direto no HTML, usando |:
{TEXTO|nl2br}
{NOME|strtoupper}
{VALOR|number_format:2:',':'.'}
{TEXTO|trim|strtoupper}
Regras:
- O valor da variável é sempre passado como primeiro argumento da função.
- Parâmetros extras vêm depois, separados por
:. - Modificadores podem ser encadeados (aplicados da esquerda para a direita).
- Qualquer função callable do PHP (ou sua própria função) pode ser usada.
Como str_replace() recebe o texto no terceiro parâmetro, a biblioteca já registra a função
global replace(), com o texto em primeiro lugar:
{TEXTO|replace:Bar:Baz}
Um modificador inexistente lança BadFunctionCallException.
Blocos
Blocos são trechos do HTML que podem ser repetidos, ou simplesmente omitidos. São delimitados por comentários HTML:
<!-- BEGIN NOME_DO_BLOCO --> ... conteúdo ... <!-- END NOME_DO_BLOCO -->
<html> <body> <table> <!-- BEGIN BLOCK_DADOS --> <tr> <td>{NOME}</td> <td>{QUANTIDADE}</td> </tr> <!-- END BLOCK_DADOS --> </table> </body> </html>
$produtos = [ ["nome" => "Sabão em Pó", "quantidade" => 15], ["nome" => "Escova de Dente", "quantidade" => 53], ["nome" => "Creme Dental", "quantidade" => 37], ]; foreach ($produtos as $p) { $tpl->NOME = $p["nome"]; $tpl->QUANTIDADE = $p["quantidade"]; $tpl->block("BLOCK_DADOS"); // "imprime" uma linha } $tpl->show();
Pontos importantes:
- Um bloco só aparece se
block()for chamado. Se nunca for chamado, ele simplesmente não existe no HTML final — é assim que se faz conteúdo condicional. - Nomes de blocos são identificados automaticamente e devem ser únicos no template
(blocos duplicados lançam
UnexpectedValueException). - Chamar
block()para um bloco inexistente lançaInvalidArgumentException. - Um bloco mal formado (sem
END, por exemplo) lançaUnexpectedValueException.
Blocos aninhados
Blocos podem conter outros blocos, sem limite de profundidade:
<!-- BEGIN BLOCK_PRODUTOS --> <table> <!-- BEGIN BLOCK_DADOS --> <tr><td>{NOME}</td><td>{QUANTIDADE}</td></tr> <!-- END BLOCK_DADOS --> </table> <!-- END BLOCK_PRODUTOS -->
Sempre que o bloco pai é exibido, os blocos filhos acumulados são "descarregados" e limpos, prontos para a próxima iteração.
Blocos automáticos por padrão
Se um bloco aninhado é exibido, todos os blocos pais são exibidos automaticamente.
Ou seja, no exemplo acima basta chamar block("BLOCK_DADOS"): o BLOCK_PRODUTOS aparece sozinho.
foreach ($produtos as $p) { $tpl->NOME = $p["nome"]; $tpl->QUANTIDADE = $p["quantidade"]; $tpl->block("BLOCK_DADOS"); } // BLOCK_PRODUTOS não precisa ser chamado $tpl->show();
Blocos FINALLY
Um bloco FINALLY é exibido apenas quando o bloco correspondente nunca foi exibido.
É o "senão" do template — perfeito para mensagens de lista vazia:
<!-- BEGIN BLOCK_DADOS --> <tr><td>{NOME}</td><td>{QUANTIDADE}</td></tr> <!-- END BLOCK_DADOS --> <tr><td colspan="2">Nenhum produto cadastrado.</td></tr> <!-- FINALLY BLOCK_DADOS -->
foreach ($produtos as $p) { // se $produtos estiver vazio... $tpl->NOME = $p["nome"]; $tpl->QUANTIDADE = $p["quantidade"]; $tpl->block("BLOCK_DADOS"); } $tpl->show(); // ...a mensagem do FINALLY aparece sozinha
Sem if, sem count(), sem código extra.
Blocos com HTML select
O caso clássico de "qual opção está selecionada":
<select name="estado"> <!-- BEGIN BLOCK_ESTADO --> <option value="{SIGLA}" {SELECTED}>{NOME}</option> <!-- END BLOCK_ESTADO --> </select>
$estados = ["RS" => "Rio Grande do Sul", "SC" => "Santa Catarina", "PR" => "Paraná"]; $atual = "SC"; foreach ($estados as $sigla => $nome) { $tpl->SIGLA = $sigla; $tpl->NOME = $nome; if ($sigla == $atual) $tpl->SELECTED = "selected"; else $tpl->clear("SELECTED"); // limpa para a próxima volta $tpl->block("BLOCK_ESTADO"); }
O método clear() é essencial aqui: sem ele, o valor da iteração anterior continuaria valendo.
Usando vários arquivos HTML
Ideal para separar cabeçalho, rodapé e miolo:
base.html:
<html> <body> <h1>Meu site</h1> {CONTEUDO} </body> </html>
miolo.html:
<p>Olá {FULANO}!</p>
$tpl = new Template("base.html"); $tpl->addFile("CONTEUDO", "miolo.html"); $tpl->FULANO = "Maria"; $tpl->show();
As variáveis e blocos do arquivo incluído passam a fazer parte do mesmo template — você
continua usando $tpl->VARIAVEL e $tpl->block(...) normalmente.
addFile() também aceita arquivos .php (.php5, .php7, .php8, .phtml, .cgi):
nesse caso o arquivo é executado e sua saída vira o valor da variável.
Guardando o conteúdo do template
$conteudo = $tpl->parse(); // retorna a string final file_put_contents("arquivo.html", $conteudo); // echo $tpl; também funciona (equivale a $tpl->show())
Usando objetos
Objetos podem ser atribuídos direto às variáveis de template — muito útil com ORMs (Doctrine, Eloquent, etc.):
<p>{USUARIO->nome}, {USUARIO->email}</p> <p>Cidade: {USUARIO->endereco->cidade}</p>
$tpl->USUARIO = $usuario;
A ordem de resolução de cada propriedade é:
- getter (
getNome()) — aceitacamelCaseesnake_case:{OBJ->minha_prop}chamagetMinhaProp() - método mágico
__get() - propriedade pública com o nome normalizado
- propriedade pública com o nome exato
- getter booleano (
isAtivo()) ArrayAccess($obj['chave'])
Se nenhum acessor for encontrado, é lançada BadMethodCallException com a mensagem exata do
que falta — em vez do erro fatal de acesso a propriedade privada.
Se o objeto no meio da cadeia for null, o resultado é string vazia (não quebra).
Detalhes:
- Objeto com
__toString(): o valor é usado direto em{VARIAVEL}(sem->). - Objeto sem
__toString()usado como{VARIAVEL}: viraObject: {"json":"do objeto"}, o que ajuda muito na hora de depurar. - Modificadores funcionam em propriedades:
{USUARIO->nome|strtoupper}.
Comentários
Comentários de template usam três traços e nunca chegam ao HTML final:
<!--- Este comentário não aparece no resultado --->
Comentários HTML normais (<!-- ... -->) são preservados.
Escapando variáveis
Para manter uma variável literal no HTML final (útil quando você gera templates a partir de
templates), insira {_} logo depois da chave de abertura:
{{_}CONTEUDO}
O resultado final conterá {CONTEUDO}.
Criando XML, CSV e outros formatos
A classe não é específica de HTML — ela trabalha com texto. Você pode usar arquivos .xml,
.csv, .txt, .svg, .json ou qualquer outro formato, com a mesma sintaxe de variáveis e
blocos (os delimitadores de bloco usam sintaxe de comentário HTML/XML).
$tpl = new Template("relatorio.csv"); header("Content-Type: text/csv"); $tpl->show();
Mensagens de erro
| Exceção | Quando acontece |
|---|---|
InvalidArgumentException |
arquivo não existe / está vazio; block() de bloco inexistente; addFile() em variável inexistente |
RuntimeException |
atribuir ou ler variável que não existe no template |
UnexpectedValueException |
bloco duplicado; bloco mal formado (BEGIN sem END) |
BadMethodCallException |
não existe acessor no objeto para a propriedade usada |
BadFunctionCallException |
modificador que não é uma função callable |
Como todas herdam de Exception, dá para tratar tudo junto:
try { $tpl = new Template("base.html"); $tpl->FULANO = "Maria"; $tpl->show(); } catch (Exception $e) { error_log($e->getMessage()); }
Precisão e desempenho
A biblioteca evita expressões regulares no caminho quente — o trabalho pesado é feito com
str_replace(), o que a torna bem mais rápida que engines antigas do estilo PHPLib. Não há
cache em disco, e nem é necessário: em praticamente todo sistema real o gargalo é o banco de
dados, não o template.
Um efeito colateral disso é que tabulações no início dos blocos são mantidas no HTML final
(elas não afetam a renderização). Se você precisa de uma reprodução fiel — por exemplo, dentro
de <pre> ou <code> — use o segundo parâmetro do construtor:
$tpl = new Template("base.html", true); // modo "accurate" (mais lento, saída exata)
Referência da API
| Método | Descrição |
|---|---|
__construct(string $filename, bool $accurate = false) |
Cria o template a partir do arquivo principal |
$tpl->VARIAVEL = $valor |
Define o valor de uma variável (aceita string, int, float, bool, null, array e objeto) |
$tpl->VARIAVEL |
Lê o valor atual de uma variável |
exists(string $varname): bool |
Informa se a variável existe no template |
clear(string $varname): void |
Limpa o valor de uma variável |
addFile(string $varname, string $filename): void |
Carrega outro arquivo dentro de uma variável |
block(string $block, bool $append = true): void |
Exibe (acumula) um bloco |
setParent(string $parent, string $block): void |
Associa manualmente um bloco filho a um pai |
parse(): string |
Retorna o conteúdo final |
show(): void |
Imprime o conteúdo final |
Licença
LGPL-2.1-or-later — a mesma da biblioteca original. Você pode usá-la como biblioteca inclusive em projetos comerciais.
Créditos ao autor original: Rael Gugelmin Cunha (raelgc/template).