PHP para Iniciantes: Estruturas de Controle - DECLARE

Facilmente confundível com uma função, declare é uma estrutura de controle que serve para declarar ou definir algumas configurações que o interpretador deve seguir no contexto onde é colocado.

E quais configurações podem ser definidas, Kiko?

Bom, no momento, apenas três: ticks, encoding e a que surgiu no PHP 7.0, strict_types. Escolhi manter os nomes em inglês porque a tradução de ticks é carrapatos e não ia fazer sentido algum com o seu papel.

E o que raios é isso então, Kiko?

Tick

É um desafio traduzir o significado dessa diretriz, mas podemos brincar com sua pronúncia, ao assimilarmos isso ao tique-taque de um relógio. Você pode não saber, mas toda operação computacional é executada mediante aos ciclos de operações do processador. Nós chamamos esses ciclos de clock, que significa relógio em inglês. Mas essa é uma nomenclatura a nível de máquina, em bits, que não é a proposta da nossa queridíssima linguagem.

Ainda assim, pode ser interessante termos a possibilidade de definir o que representa um ciclo de instrução do nosso interpretador. Esse ciclo, a nível das instruções do PHP, é chamado de tick. E dito isso, é impossível afirmar que tick se tornará obsoleto, pois é uma nomenclatura extremamente minuciosa e com referências plausíveis. Eu coloco dessa forma pois alguns sites compartilharam uma informação falsa de que seria removido da linguagem quando ainda estávamos no PHP 5.6... E eis que segue firme até agora, hehe.

Voltando ao assunto, a cada "tique" do "relógio", o interpretador lê N instruções. Esse N deve ser um número natural maior ou igual a 1. Ou seja, um tique pode ser tanto somente uma instrução quanto cinco. Nós podemos declarar isso de forma simples pela estrutura declare com o comando declare(ticks=2);, por exemplo.

Para fazer experimentos com isso, nós podemos usar a função register_tick_function(), que serve para definir uma função para executar a cada tique.

<?php // não execute isso em um interpretador online... crie um arquivo e rode na sua máquina ;)
declare(ticks=2);
$contador = 0;
register_tick_function(function() use (&$contador) {
    echo 'tick: ' . ++$contador . PHP_EOL;
});
for($i = 0; $i < 20; $i++) {
    echo 'instrução'. PHP_EOL;
}

Resultado:

instrução
tick: 1
instrução
tick: 2
instrução
tick: 3
instrução
tick: 4
instrução
tick: 5
instrução
tick: 6
instrução
tick: 7
instrução
tick: 8
instrução
tick: 9
instrução
tick: 10
instrução
tick: 11
instrução
tick: 12
instrução
tick: 13
instrução
tick: 14
instrução
tick: 15
instrução
tick: 16
instrução
tick: 17
instrução
tick: 18
instrução
tick: 19
instrução
tick: 20
tick: 21

Trocando o ticks=2 por ticks=1, o último tick acaba sendo o 22. Trocando por ticks=4, acontece isso aqui:

instrução
tick: 1
instrução
instrução
instrução
tick: 2
instrução
instrução
instrução
tick: 3
instrução
instrução
instrução
tick: 4
instrução
instrução
instrução
tick: 5
instrução
instrução
instrução
tick: 6
instrução
instrução
instrução
tick: 7
instrução

Kiko, por que nesse caso não acaba com tick?

Porque o código encerrou antes do número necessário de instruções para acionar a função que registramos.

Onde eu posso usar esse tipo de recurso?

Bom, são aplicações muito específicas. A primeira ideia que me vem em mente seria sobre observabilidade, por exemplo, monitorar algum dado da máquina a cada tique. Também podemos usar esse recurso para preparar um Graceful Shutdown (artigo do mestre Leonardo do Carmo), porém tem formas melhores de se fazer isso (como mencionado no artigo aí).

Mas no geral, é contraindicado usar esse tipo de controle em ambientes web, ou seja, 99% das aplicações PHP (fonte do número: voices from my mind). Se você conhecer algum case onde solucionaram problemas de performance aumentando o número de instruções por tick, por favor, manda aí nos comentários!

No geral, eu realmente acredito que você não vai precisar mexer nisso tão cedo, se for realmente um iniciante.

Obs.: há alguns comportamentos diferentes entre as versões de PHP antes e depois do 7.0. Isso não é papo de iniciante, então recomendo que se aprofunde um pouco mais nas documentações oficiais de acordo com o versionamento que irá trabalhar, beleza?

Encoding

Quando falamos de texto, geralmente pensamos em string, certo? E muitas vezes, quando precisamos transferir texto para algum lugar, precisamos informar a sua codificação para que o receptor possa entender ou desenhar os símbolos corretamente.

Se não houver essa informação, o receptor irá usar sua codificação padrão e, quando encontrar um símbolo que não existe em seu mapa de caracteres, irá exibir uma interrogação.

Isso é o que geralmente acontece em sites quando o HTML não possui nenhuma definição de encoding ou charset e você recebe alguma palavra com acentuação. Vira uma interrogação bem feia.

No caso do PHP, isso serve para dizer em qual encoding você escreveu o seu código. Serve para permitir que você use letras relativas às das palavras-chave em outras escritas. Assim, o interpretador consegue entender os seus comandos.

No geral, podemos parametrizar essa diretriz no php.ini, o arquivo de configurações do interpretador. Mas vai que, por algum motivo desconhecido, parte do seu código está em UTF-8 e outra está em CP932?

Bom, se for o caso, antes de escrever o código em codificações malucas, é bom dar uma olhada nas codificações suportadas na tabela da documentação oficial.

Outro detalhe, é que essa diretriz só pode ser parametrizada com a extensão de MultiByte (a famosa mbstring). Se não tiver isso instalado e tentar atribuir uma codificação, você pode receber um erro (a depender da versão do PHP).

Tá, Kiko, mas como eu informo a codificação?

Ah sim, quase esqueci.

<?php
declare(encoding='CP932');

// ... seu código

Strict Types

Essa aqui você já sabe, que eu sei. Ao menos se leu todos os meus artigos até aqui, você deve lembrar que mencionei lá no artigo sobre Declaração de Tipagens.

Mas só para resumir, caso não tenha lido: você pode configurar o interpretador para que ele use tipagens rígidas. Isso não significa que irá tornar a linguagem em tipagem forçada, apenas rígida. Ao entrar em uma função ou método com tipagem(ns) declarada(s), se o dado não corresponder a um dos tipos anunciados, o PHP irá encerrar o processo com um FatalError indicando o tipo que esperava.

Assim, você pode manter a qualidade do código elevada sem tomar surpresas como conversões inesperadas. Enfim, tem um bom exemplo lá no artigo, dá uma olhada!

Sobre a forma de uso:

<?php
declare(strict_types=1);

function soma(int $a, int $b): int
{
    return $a + $b;
}

var_dump(soma(1.1, 3)); // FatalError: a entrada precisa ser int, informei float.
<?php
declare(strict_types=1);

function soma(int $a, int $b): int
{
    return $a + $b + 1.1; // FatalError: falou que retornava int e retornou float
}

var_dump(soma(1, 3));

Outros detalhes

No geral, a estrutura declare é similar as outras, isto é, pode ter um contexto interno específico. Se você deseja modificar, por exemplo, o ticks em uma pequena parte do código, você pode encapsular essa parte com chaves ({ }), ficando declare(ticks=3) { ... }.

Nesse cenário, as diretrizes encoding e strict_types são exceções. Você não pode misturar encodings num mesmo arquivo, por isso, esse tipo de declarativa só pode ser global. Além disso, não faz sentido forçar tipagem rígida só em um espaço do código... Ou você usa, ou você não usa.

JoJo, think on it

Então eu posso modificar os ticks só para um trecho do código, Kiko?

Sim.

Mas Kiko, se são só três diretrizes e duas são exceções, não seria o ticks a exceção?

Não. Como falei, o comportamento padrão é o de permitir ter a sintaxe com chaves. Acontece que não temos como saber quantas diretrizes podem ser incluídas no futuro. As novas podem não ter nenhuma especificação para alterar o padrão, sabe? Por isso vamos destacar as duas como exceções mesmo.

Outro detalhe é que os valores inseridos na declaração de diretrizes precisa ser um tipo de dados primitivo. Não pode ser expressões nem constantes, nada disso. O strict_types mesmo, precisa estar no topo do código.

Um ponto de observação pessoal que gostaria de deixar aqui é: evitem duplicar código. Se o seu projeto vai usar tipagem rígida, ou você coloca na raiz das chamadas, ou você coloca na configuração do PHP. Replicar declare(strict_types=1); em todos os arquivos só vai deixar isso espalhado... E se em alguma versão do PHP mudarem o nome para strong_types? Haja replace, hein? E se o seu projeto não usa, evite criar exceções. Isso pode gerar muita confusão, no fim das contas. Beleza?

E por hoje é só! Espero que tenham gostado do artigo... Dessa vez, sem implementações, porque esse aqui é mais para configurar o interpretador, certo? Deixe quieto, vá. No próximo artigo falaremos sobre a estrutura return... E não, return não é uma exclusividade de funções. Vou bolar uns exemplos doidos pra esse artigo, pode esperar!

Inté!!