PHP para Iniciantes: Funções - Definidas pelo Usuário
Até aqui, já vimos uma série de exemplos sobre funções na prática, desde a criação até a usabilidade de uma, mas nada oficial como material de estudo, apenas como exemplo do assunto que estávamos falando na hora. Dito isso, precisamos dar dez passos para trás para mostrar o que exatamente é uma função definida pelo usuário...
Peraí... Quem é esse usuário, Kiko?
Você, ué. O usuário da compilação é quem escreveu o código a ser compilado. Então se você escreveu uma função no código, essa função é chamada função definida pelo usuário, afinal, como vimos no artigo anterior, já temos as funções internas.
Além disso, essas funções definidas também são conhecidas como funções nomeadas, onde obrigatoriamente cada função deve ter um nome único. As regras de escrita de uma função são as mesmas de uma variável, exceto que não colocamos o operador de variável na frente ($
). Ou seja, o primeiro caractere deve ser uma letra ou um underline (_
) e as demais podem ser, também, números.
No caso de funções, as letras são case insensitive, portanto, não importa a forma que você as escreva (tudo maiúsculo, tudo minúsculo, tudo bagunçado), desde que tenha as mesmas letras na mesma sequência, a função será chamada. Mesmo assim, é bom senso escrever exatamente do mesmíssimo jeito que definiu no momento da declaração, beleza?
Reforçando: funções nomeadas são constantes, isto é, você não pode redefini-la. No máximo criar outra com outro nome. Mesmo variando o maiúsculo e/ou minúsculo, como a declaração é case insensitive, ainda daria conflito.
E mais uma observação: as funções não são declaradas no momento da evaluação (leia-se interpretação com dados de entrada) do código e sim na compilação, ou seja, você pode chamar a função antes de definí-la, desde que ela realmente seja definida posteriormente sem nenhuma dependência da interpretação de uma expressão.
Além disso tudo tem outro ponto importantíssimo: toda função nomeada tem contexto GLOBAL. Mesmo que você a crie dentro de mil laços, ela ainda vai ser acessível do lado de fora de todos eles. Da mesma forma, você não vai conseguir declarar a função mais de uma vez.
E aqui acabamos com os litle details hehehehehehehehe.
Calma, não se desespere, é claro que eu vou colocar tudo o que falei em prática. Vamos revisar cada ponto mencionado em forma de exemplos:
1 - Uma função deve ter um nome único
Considere o seguinte arquivo, responsável por definir a função nomeUnico()
:
<?php // nomeUnico.php
function nomeUnico() {
echo 'Nome Único!';
}
E considere esse outro arquivo, que aciona essa declaração incluindo esse arquivo dentro de si:
<?php // header.php
require(__DIR__ . '/nomeUnico.php');
nomeUnico(); // imprime 'Nome Único!'
E então, esse outro arquivo que inclui o header.php
... Mas acidentalmente incluíram, também, o nomeUnico.php
:
<?php // index.php
require(__DIR__ . '/header.php');
require(__DIR__ . '/nomeUnico.php'); // Fatal error: Cannot redeclare nomeUnico()
Esse erro só aconteceu porque a função em si já havia sido declarada no primeiro require
executado dentro do arquivo header.php
. E para solucionar esse problema, tem três jeitos:
A - [Best Developer Choice]
Pare de fazer descoberta de funções/classes na mão, use namespace com spl_autoload
!
Mas tudo bem se não quiser ver isso agora, afinal eu não expliquei nada disso. Porém essa é uma dica de ouro hein? Imagina só incluir uma função e/ou classe somente quando ainda não foi definida? Maravilhoso. E ainda garante um padrão PSR-4 no projeto, se fizer certinho... Ah, maravilha.
B - Limite a importação da função para uma única vez com require_once
Se o arquivo nomeUnico.php
serve somente para declarar a função, você pode controlar bem o código ao limitar sua inclusão para somente uma única vez adicionando a terminologia _once
no require
, modificando os arquivos header.php
e index.php
para, respectivamente:
<?php // header.php
require_once(__DIR__ . '/nomeUnico.php');
nomeUnico(); // imprime 'Nome Único!'
<?php // index.php
require(__DIR__ . '/header.php');
require_once(__DIR__ . '/nomeUnico.php'); // nada acontece feijoada
Assim, desde que todo require
desse arquivo esteja com essa defesa, nada irá declarar a função duas vezes.
C - [Best Beginner Choice]
Verifique se a função foi declarada antes de declará-la
Se você sabe que há um risco enorme de outro desenvolvedor desavisado incluir a função sem a terminologia _once
(e quiser retirar essa responsabilidade de conhecer tudo o que acontece em todo lugar), você pode deixar a declaração segura encapsulando-a com uma verificação simples usando a função function_exists()
, que retorna true
quando já existe uma função declarada no nome informado e false
quando não.
Ou seja, modificando somente o arquivo nomeUnico.php
para:
<?php // nomeUnico.php
if (!function_exists('nomeUnico')) {
function nomeUnico() {
echo 'Nome único!';
}
}
Se você já lidou com WordPress, provavelmente já viu um monte desses espalhados por aí... Se encontrar de novo e já estiver manjando de spl_autoload
, por favor, resolve esse débito técnico, ok?
Eu ouvi um ok??!
Não tem como eu ter ouvido um ok, mas tudo bem. Vamos para o próximo ponto!
2 - As regras de nomenclatura são as mesmas das variáveis
E aqui não tem o que discutir, apenas sentir
<?php
function ehUmNomeValido() {
return 'oi';
}
function _tambemEhUmNomeValido() {
return 'vc';
}
function Tambem3h_UmNomeValido() {
return 'vem';
}
// daqui pra cima é sucesso
// daqui pra baixo é erro
function 1naoEhUmNomeValido() {
return 'sempre';
}
function $tbmNao() {
return 'aqui';
}
function mt Menos Assim() {
return '?';
}
3 - O uso das funções é case insensitive
<?php
function nomeUnico() {
echo 'Nome único!' . PHP_EOL;
}
// mesmo que você declare assim, com tudo minúsculo e o U maiúsculo
// você pode chamar do jeito que quiser
NOMEUNICO();
nomeunico();
NoMeUnIcO();
NOMEuNICO();
// você só não pode colocar caracteres diferentes da ordem da escrita
N0MEUNICO(); // erro
_nomeUnico(); // erro
Da mesma forma, respeitando o primero ponto, você não pode escrever outra função com a mesma nomenclatura mesmo variando as letras maiúsculas e minúsculas.
<?php
function nomeUnico() {
echo 'Nome único!' . PHP_EOL;
}
// aqui vai dar erro
function nomeunico() {
echo 'Nome único!' . PHP_EOL;
}
4 - As funções não são declaradas no momento da evaluação
Se você escreve uma função no escopo natural do código, sem nenhuma dependência (como aquele if
que criei), você poderá escrever sua execução antes mesmo de definí-la sequencialmente. Por exemplo:
<?php
nomeUnico();
function nomeUnico() {
return 'Funciona!';
}
Isso aqui só funciona porque o PHP dá uma compilada no seu código antes de atribuir valores à chamada. Por isso ele consegue saber que a função existe em algum lugar e chamá-la corretamente. Entretanto, se a declaração da sua função depender de uma expressão, aí não funciona, pois a resolução de expressões é feita no momento de evaluação, onde há dependência de um dado.
<?php
nomeUnico();
if (!function_exists('nomeUnico')) { // expressão dependente
function nomeUnico() {
return 'Não funciona =/';
}
}
Mesmo em casos literais isso acontece, pois também são considerados expressões. Experimente trocar o !function_exists('nomeUnico')
por true
.
5 - Toda função tem contexto GLOBAL
E é fato:
<?php
function declaraNomeUnico() {
function nomeUnico() {
echo 'Funciona!';
}
}
declaraNomeUnico();
nomeUnico(); // mesmo sendo declarada dentro da função, podemos chamá-la do lado de fora
Enfim, com todos esses exemplos, você deve ter percebido que a escrita segue esse passo-a-passo:
- começa com
function
; - depois colocamos o nome único da função;
- daí abrimos parênteses (
(
), onde, nos exemplos acima, ficaram todos vazios; - depois fechamos os parênteses (
)
); - e, em seguida, abrimos o bloco de código a ser executado pela função que estamos definindo, encapsulando com chaves (
{}
).
O que ficaria entre os parênteses, Kiko?
Os argumentos, que é o assunto do nosso próximo artigo, pois é bem extenso. Mas são como se fossem variáveis internas, onde você pode definir o tipo de dado esperado, um valor padrão, etc. Se você já estiver lidando com PHP 8, tem um recurso bem interessante chamado Named Arguments ou Argumentos Nomeados que também abordarei no próximo artigo. Por tanto, não esqueça de vir dar uma lida!
E por hoje é só! Curtiu?! Comenta e compartilha! Ainda falta um bocado de coisa para falar sobre funções, mas aqui já deu pra dar um overview básico de como escrevê-las. Nos próximos você só vai aprender como deixá-las mais complexas, hehehehehe. Ah, não esquece de responder minha pergunta subliminar que deixei nos códigos, hein?
Inté!!