# PHP para Iniciantes: Constantes - Sintaxe

Agora que você já sabe o básico sobre **constantes**, vamos falar um pouco sobre sua sintaxe e as possíveis formas de declaração. E sim, o interpretador tem ações diferentes de acordo com a forma que você declara uma constante. Bateu a curiosidade? Então vamos.

## A escrita

As regras de escrita de uma constante são iguais às regras de variáveis, exceto que constante não pode ser precedida pelo caractere `$`. Dito isso, outra grande diferença entre eles - a mais óbvia - é que constantes não podem ser alteradas nem "anuladas" depois de receber um valor, isto é, uma vez declarado um dado constante, essa informação permanecerá inalterada até o fim da execução do script.

Voltando a falar de escrita, os caracteres do nome de uma constante devem seguir as regras:

- o primeiro deve ser uma letra ou underline;
- os demais, se houver, devem ser letra, número e/ou underline.

O que nos leva aos exemplos:

- `OI123`;
- `DB_HOST`;
- `__PARECE_LEGAL__` ~ `__MAS_NAO_EH__`;
- etc.

Obs.: esse último exemplo começando e encerrando com underlines é extremamente arriscado, pois é como as constantes mágicas do PHP são escritas. Isso significa dizer que, se por um acidente do destino alguma versão futura do PHP criar uma constante mágica com o mesmo nome que você estava usando, teu projeto vai parar de rodar, rs. **Evite fazer constantes iniciando e terminando com underline!**

## A declaração (owwwn -Q)

Para declarar uma constante, nós podemos usar tanto a função [`define()`](https://www.php.net/manual/pt_BR/function.define.php) quanto a palavra reservada `const`.

> E qual a diferença, Kiko?

`const` tem uma limitação gritante: você só pode declarar dessa forma inserindo valores de **tipos de dados primitivos escalares** ou **arrays contendo somente tipos (...) escalares**. Você lembra quais são? Vale a pena revisar na [Introdução aos tipos de dados primitivos](https://blog.kaiquegarcia.dev/php-para-iniciantes-tipos-de-dados-primitivos-introducao), mas vou resumir: booleanos, inteiros, pontos flutuantes e strings.

É dito que também é possível criar constantes com o tipo especial `resource`, mas dado que se trata de uma referência a um recurso externo à aplicação, é melhor não tentar fazer isso. Você pode gerar um gravíssimo problema de desempenho (onde um recurso permanece inalterável e, por exemplo, deixa de transmitir bytes - ou até mesmo é impedido de encerrar algo).

> Ok... Então se usarmos a função `declare` podemos tornar um objeto constante, Kiko?

### NÃO!

Cof, desculpe, **não**. Esqueci de mencionar a diferença né? É bem simples... Com `const`, você somente pode usar dados constantes, jamais expressões. Então você não consegue, por exemplo, usar o retorno de uma função na definição da constante.

Com o `define`, você consegue!

```php
<?php

$umaFuncao = function() {
    return 'umRetorno';
};

const CONSTANTE_QUEBRADA = $umaFuncao(); // isso vai dar erro
define('CONSTANTE_OK', $umaFuncao()); // isso vai funcionar
```

> Tá, mas por que isso é importante, Kiko?

Acontece que, algumas vezes na vida, nós podemos precisar criar uma constante que tem mais de uma possibilidade de existir. **Ela não é dinâmica** - o dado precisa ser constante ao longo do ciclo de vida da execução do script. Porém, o dado que será inserido pode variar.

*Obs.: o exemplo a seguir é uma ofensa ao conceito de `i18n` (internacionalização). Considere apenas como um exemplo amigável para dar contexto, jamais faça isso, rs.*

Por exemplo, digamos que eu resolvi criar uma constante com meu nome e sobrenome. Se você estiver acessando de países ocidentais, "nome + sobrenome" estará na ordem correta. Já em países orientais, não. Como você resolveria essa troca? Com um `if`?

```php
<?php

// suponha que a variável $ocidental é um booleano que indica se é ou não, okay?
if ($ocidental) {
    const NOME = 'Kaique Garcia';
} else {
    const NOME = 'Garcia Kaique';
}
```

Ok, eu sei que é um exemplo bem besta pois poderia ser reduzido a uma linha com **equação ternária**, mas ainda preciso considerar que você não sabe o que é isso pois ainda não mencionei, beleza? *(e se realmente não souber, não tem problema! Pode pesquisar se quiser, mas só vamos falar disso lááá pra frente!)*

> Ah, Kiko, como você faria?

Olha, se tem uma certa complexidade na hora de gerar um dado que será constante, por que não centralizar o gerador dessa informação em uma outra classe e apenas capturar o resultado na declaração da constante? Por exemplo:

```php
<?php //NameBuilder.php

class NameBuilder { // BIRLLL
    public function __invoke(bool $isOcidental): string
    {
        if ($isOcidental) {
            return 'Kaique Garcia';
        }
        return 'Garcia Kaique';
    }
}
```

E aí substituiríamos aquela chamada por:

```php
<?php // index.php

require_once("NameBuilder.php");
$nameBuilder = new NameBuilder();

// para testar, mude os valores manualmente para ver na prática
$ocidental = true;
define('NOME', $nameBuilder($ocidental));

var_dump(NOME); // string(Kaique Garcia), no caso do valor informado acima
```

Parece mais organizado? Bem, só funciona com a função `define()`! Pode fazer o teste trocando pela declaração `const`.

Você realmente pode se deparar com situações onde será necessário criar uma constante "dinâmica". Pensando nisso, é possível consultar uma constante a partir de uma `string` representando seu nome, seja pra saber se ela existe (função [`defined()`](https://www.php.net/manual/pt_BR/function.defined.php), um `d` no final) ou qual o seu valor ([`constant()`](https://www.php.net/manual/pt_BR/function.constant.php)). Por exemplo:

```php
<?php

// OBS.: esse teste pode não funcionar em todos os ambientes. Se você rodar e se deperar com erro dizendo que a função 'constant' não existe, experimente rodar no Shell do PHP, através do comando no terminal "php -a"

const MEU_URSINHO = 'POO';
const POO = 'QUE';

$constante = 'MEU_URSINHO';

// como saber se a constante da string presente na var $constante existe?
$existe = defined($constante); // bool
var_dump($existe); // bool(true)

// como resgatar o valor da constante?
$valor = constant($constante);
var_dump($valor); // string(POO)

// como saber qual constante utilizei? ah...
var_dump($constante); // string(MEU_URSINHO)

// e no caso desse exemplo da pra pegar a constante da constante, que nem variável variável, mas isso é loucura pessoal, não precisa quebrar a cabeça pensando nisso
var_dump(constant(constant($constante))); // string(QUE)
```

## Obtendo a lista de constantes declaradas

Isso é bem simples, tem uma função pronta pra você: [`get_defined_constants()`](https://www.php.net/manual/pt_BR/function.get-defined-constants.php). Ele retorna um array com a assinatura `<string, mixed>`, que significa que as chaves são textos e os valores podem ser qualquer tipo de dado (de acordo com as regras da declaração de constantes). A chave representará o nome da constante. Por exemplo:

```php
<?php

const NOME = 'Kaique Garcia';

var_dump(get_defined_constants()); // array( (... todas as constantes do PHP), "NOME" => "Kaique Garcia");
```

## Constantes em classes

Enquanto escrevemos uma classe, a única forma de declarar uma constante vinculada a ela é usando a palavra `const`. Nesse cenário, a constante poderá ter sua visibilidade restringida. É o mesmo caso dos atributos: públicos (`public`), protegidos (`protected`) e privados (`private`). Se você não define a visibilidade, ela usa a padrão, que é pública. É recomendado que sempre determine uma para evitar ambiguidades... Afinal, vai que o PHP resolve mudar o padrão, né?

Então temos:

```php
<?php

class ExemploPai {
    public const PUBLICA = 1;
    protected const PROTEGIDA = 2;
    private const PRIVADA = 3;

    public function __invoke(): int
    {
        // dentro dessa classe, todas as constantes acimas são acessíveis
        return self::PRIVADA;
    }
}

class ExemploFilho extends ExemploPai {
    public function __invoke(): int
    {
        // dentro dessa classe que é originada a partir da classe ExemploPai
        // somente as constantes públicas e protegidas são acessíveis
        return self::PROTEGIDA;
    }
}

class ExemploForasteiro {
    public function __invoke(): int
    {
        // dentro daqui, que não é originada a partir da classe ExemploPai nem ExemploFilho,
        // somente é possível pegar a constante pública
        // repare que, como ExemploFilho foi criado a partir de ExemploPai, ele tem a mesma constante vinculada a si!
        return ExemploPai::PUBLICA + ExemploFilho::PUBLICA;
    }
}

$pai = new ExemploPai;
$filho = new ExemploFilho;
$forasteiro = new ExemploForasteiro;

var_dump($pai()); // const PRIVADA = int(3)
var_dump($filho()); // const PROTEGIDA = int(2)
var_dump($forasteiro()); // const PUBLICA + const PUBLICA = int(1) + int(1) = int(2)
```

# Conclusão

Devemos refletir com sabedoria antes de encher nossos códigos com `const` ou `define`. Não faz sentido usar `define` se o seu dado é do tipo escalar. Você pode economizar muito mais espaço e melhorar a legibilidade do código com a declaração mais bonita. Já se o tipo tem alguma condição para ser definido, então arrume o seu código para centralizar esse controle em outro lugar e declare com o `define`.

Se fizer sentido uma constante ser uma informação de uma classe, usa o `const` com a definição de visibilidade **necessária**. Não crie `public` se a informação só interessar à classe, beleza?

Curtiu? Comenta e compartilha! Quero ver pessoas empolgadas com PHP o tempo inteiro, hehe. No próximo artigo falaremos sobre **constantes pré-definidas**. Não vai ser sobre todas, porque são muitas, mas falaremos das principais que o interpretador deixa disponível para consultarmos. Não perca!

**Inté!**
