Curso de PHP: #14 - Funções

Curso de PHP: #14 - Funções

·

11 min read

Fala escoteiro, tudo na mais perfeita ordem? Em nosso post anterior nós demos uma relaxada e vimos um assunto mais tranquilinho, que foi Operadores de atribuição composta. Para o post de hoje eu vou pedir que você desligue o celular, tire o cachorro da sala, e preste muita atenção. O assunto em si não é tão complicado, mas requer bastante atenção para não perder nenhum detalhe, uma vez que esse é o assunto mais importante do curso e vai lhe dar subsídio para você evoluir como programador e aprender dentre outras coisas Programação Orientada a Objetos.

O que é uma função?

Um função nada mais é que um conjunto de código, previamente escrito por você ou por outra pessoa que pode ou não receber parâmetros de entrada, realizar alguma operação e devolver ou não uma resposta.

Pense num moedor de café

image.png Foto: raffelestore.com.br

Nós temos 3 partes importantes:

  1. Entrada de dados: Nesse caso poderíamos entender como a inserção dos grão de café no reservatório.
  2. Processamento: O ato de triturar o café
  3. Saída: O pó de café

Uma função trabalha de maneira análoga a esse exemplo. Até o momento a gente fez uso de algumas funções como por exemplo: var_dump(), print_r() e count(), em todas elas nós tínhamos algum valor de entrada que era passado por parâmetro para elas, havia um processamento interno pela função, e era devolvida uma resposta.

Exemplo:

O PHP tem nativamente centenas de funções que realizam as mais variadas ações, uma delas é o strlen(), vamos acessar o site oficial do PHP e ver a documentação para entender o que essa função faz e como ela trabalha.

Documentação da função: https://www.php.net/manual/pt_BR/function.strlen.php

Ao acessar o endereço acima você verá algo similar a isso:

image.png

Praticamente todas as funções do PHP seguem esse mesmo padrão (algumas podem não ter tradução para português).

  1. Nome da função, nesse caso strlen
  2. O que ela se propõe a fazer e em quais versões do PHP ela está disponível
  3. O que ela espera receber por parâmetro, ou seja, o que ela espera que você informe a ela.
  4. O que você pode esperar como resposta.

Vamos ver essa função em ação?

<?php

$plataforma = "Acampamento Dev";

echo strlen($plataforma);

Ao executar esse programa você verá que a resposta será o número 15, o que nos leva a conclusão de que até mesmo o "espaço em branco" é considerado um caractere e também é levado em consideração na hora de contar.

Vamos agora fazer uma pequena mudança nesse código. Ao invés de analisarmos o tamanho da string "Acampamento Dev", vamos calcular o tamanho da string "João".

<?php

$nome = "João";

echo strlen($nome);

Ué, não deveria ser 4? Por que ele imprimiu 5?

Calma, não tem nada de errado ai. O PHP entende a acentuação como um caractere a parte, logo ele conta "J", "o", "a", "o" e "~".

Mas e se eu não quiser que ele trabalhe dessa forma, já que pra mim não é interessante que ele trabalhe assim?

Simples, basta usar a função mb_strlen()

<?php

$nome = "João";

echo mb_strlen($nome);

Diversas outras funções nativas do PHP também tem essa versão com e sem o prefixo "mb_" e sempre que você ver isso, lembre-se que tem a ver com a forma como ela lida com a codificação de caracteres.

Anatomia de uma função

Uma função sempre terá um nome (vamos desconsiderar as funções anônimas por enquanto) e assim como as variáveis esses nomes devem:

  1. Seguir o padrão camelCase ou snake_case que vimos no post sobre variáveis.
  2. Não deve iniciar com números ou caracteres especiais.
  3. Não pode ter espaço entre as palavras que foram o nome.

Criando funções personalizadas

Como vimos até agora, o PHP tem diversas funções já prontas, mas é muito comum que nós desenvolvedores precisemos criar nossas próprias funções. O PHP nos permite fazer isso é bem simples. Veja esse exemplo:

<?php

function dizerOla() {
    echo "Olá!";
}

dizerOla();

Vamos analisar o código acima...

  1. Sempre que vamos definir nossas próprias funções, não utilizamos a palavra reservada function, essa palavra informa ao interpretador PHP que nós estão definindo uma nova função.
  2. Na sequência informamos o nome da função que estamos criando. Nesse exemplo o nome da função é dizerOla (utilizei o padrão camelCase).
  3. Dentro do bloco delimitado pelas { } temos o código que será executado sempre que essa função for invocada. Nesse exemplo, ele apenas imprime a string "Olá!".
  4. Uma vez que a função está pronta, podemos invoca-la da mesma foram que fizemos todas as outras que usamos até agora, ou seja, digitamos o nome da função seguida de parênteses.

Agora eu posso chamar essa função quantas vezes eu quiser, que a resposta sempre será imprimir no console a string "Olá!".

Passando parâmetros personalizados para nossas funções

Usando novamente a analogia do moedor de café, as funções podem receber parâmetros de entrada, e para passar esses parâmetros para nossas funções é muito simples, basta definir algumas variáveis separadas por virgula dentro dos parênteses da função no momento de sua criação.

Exemplo:

<?php

function dizerOla($nome, $sobrenome) {
    echo "Olá! $nome $sobrenome";
}

dizerOla("Paulo", "Reis");

A função acima espera receber 2 parâmetros, sendo $nome e $sobrenome e vai concatena-los com a string "Olá!" para só então imprimir no console.

Uma vez que uma função espere receber parâmetros, você é obrigado a informá-los, se você esquecer o PHP vai acusar um erro.

Exemplo:

<?php

function dizerOla($nome, $sobrenome) {
    echo "Olá! $nome $sobrenome";
}

dizerOla("Paulo");

Resultado:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function dizerOla(), 1 passed in /home/runner/CursoPHPAcampamentoDev/main.php on line 7 and exactly 2 expected in /home/runner/CursoPHPAcampamentoDev/main.php:3
Stack trace:
#0 /home/runner/CursoPHPAcampamentoDev/main.php(7): dizerOla('Paulo')
#1 {main}
  thrown in /home/runner/CursoPHPAcampamentoDev/main.php on line 3
exit status 255

O mais legal disso tudo é que o PHP nos informa qual erro aconteceu e onde exatamente ele aconteceu. Vamos dar uma olhada nessa mensagem de erro:

  1. Fatal error: Na tradução livre "Erro fatal" ou seja, esse tipo de erro é o pior de todos, porque ele para imediatamente a execução do programa. Existem alguns outros tipos de erro no PHP, mas não vamos nos preocupar com isso agora.
  2. Uncaught ArgumentCountError: Se traduzirmos encontraremos algo como: "Erro de contagem de argumentos não capturados". Isso significa que o PHP entendeu que a função em questão precisava de uma quantidade específica de argumentos mas recebeu outra quantidade. Mas... O que são esses argumentos? Os argumentos são os parâmetros da função 🙂.
  3. Too few arguments to function dizerOla(): Isso apenas reforça a informação acima, mas agora ele já te diz onde está o problema, ou seja, na função dizerOla() e ainda diz que 1 argumento foi passado, mas ele esperava exatamente 2.

Parâmetros opcionais

Imagine que você vai ao cinema com sua namorada ou namorado e quando você vai comprar o ingresso o atendente fala:

Esse filme é para maiores de 14 anos, então preciso que vocês me informem alguns dados. Como Nome completo e Ano de nascimento. Nós também estamos fazendo uma promoção para nossos clientes enviando-lhes um cupom por e-mail. Para participar basta informar o seu CPF e E-mail.

Analisando o texto acima a gente tem 2 tipos de dados:

Dados obrigatórios, sem os quais eu não posso assistir o filme

  • Nome completo
  • Ano de nascimento

Dados opcionais, que eu só informo se eu quiser participar da promoção

  • CPF
  • E-mail

Se fossemos criar uma função para receber esse cadastro, os parâmetros CPF e E-mail deveriam ser opcionais, certo? Mas como podemos fazer isso com o PHP?

É bem simples na verdade:

<?php

function cadastro($nome, $anoNascimento, $cpf = "", $email = "") {
    $dadosCliente = [
        "nome" => $nome,
        "anoNascimento" => $anoNascimento,
        "cpf" => $cpf,
        "email" => $email        
    ];

    print_r($dadosCliente);
}

cadastro("Paulo", 1985);

Quando no momento da criação da função você já atribui um valor para um determinado parâmetro, isso significa que ele funcionará da seguinte forma:

Se quem chamar a função informar um valor, esse valor será usado, do contrário, o valor padrão, ou seja, o valor definido no momento da criação da função prevalecerá. Logo, esse parâmetro se torna opcional.

Retornando valores ao invés de imprimi-los

Até agora todos os nossos exemplos foram bem simples, porém nem sempre vamos precisar receber um parâmetro e imprimi-lo na tela.

Imagine que você está tentando logar em sistema como o Gmail por exemplo, o que você faria caso você esquecesse sua senha? Provavelmente clicaria em "Esqueci minha senha". Se algum dia na vida você já precisou recuperar uma senha, você deve imaginar como essa operação funciona.

  1. Informo o meu e-mail
  2. O sistema analisa se existe uma conta associada ao meu e-mail
  3. É enviado um e-mail para mim com um link para redefinir a minha senha.

Ou seja, nesse caso não precisamos imprimir nada, mas sim devolver uma informação "nesse caso o e-mail da pessoa" para outra função que se encarregará de disparar o e-mail.

Vamos ver na prática como esse tipo de função trabalha.

<?php

function temDisciplinaZerada($notas) {
    foreach($notas as $nota) {
        if($nota == 0) {
            return true;
        }
    }

    return false;
}

$notasDisciplinas = [
    "portugues" => 5,
    "matematica" => 1,
    "ingles" => 0,
    "geografia" => 7
];

if (temDisciplinaZerada($notasDisciplinas)) {
    echo "Você zerou pelo menos uma disciplina!";
} else {
    echo "Você não zerou nenhuma disciplina";
}

Não ficou muito claro? Vamos então analisar linha a linha esse código

  • Primeiro nós definimos uma função chamada temDisciplinaZerada, esse nome foi escolhido por mim, poderia ser qualquer outro, mas eu escolhi um nome que sugere o que a função faz que nesse caso é verificar se em um array tem pelo menos uma disciplina com nota igual a zero.
  • Durante a definição da função informamos que essa função esperará receber apenas um parâmetro que será um Array com todas as notas do aluno.
  • Em seguida fazemos um foreach (ou seja, percorremos todas as posições desse array) e para cada item o PHP salvará o seu conteúdo na variável $nota (no singular)
  • A cada volta do loop (laço de repetição) vamos executar um if que analisará: "A nota atual é igual a zero? Se sim, executaremos um RETURN.

Sempre que quisermos que uma função devolva algum valor para o ponto do programa que a invocou, utilizamos a palavra reservada return e tudo que vir após ela será devolvido. Porém tome muito cuidado quando o interpretador PHP executar o return dentro de uma função ele devolve o valor seguinte e para imediatamente a execução da função, ou seja, tudo que tiver abaixo do return será ignorado.

  • Ou seja, nesse nosso exemplo ele vai passar pela nota de português, que é 5, e não vai entrar no bloco do IF, logo o return não será executado. Vai passar pela nota de matemática e novamente o IF não terá sua condição satisfeita então o return também não será executado, porém ao chegar na nota de inglês a condição do if será satisfeita e nesse caso o return será executado devolvendo o valor Booleano true sendo assim a função terá seu funcionamento interrompido e a nota de geografia sequer chegará a ser analisada.
  • Se nenhuma nota fosse igual a zero o if nunca teria sua condição satisfeita, logo, o return a ser executado seria o return do false.

Beleza, já entendemos como a função funciona, mas e o restante do código?

  • Primeiro criamos uma variável $notasDisciplinas e atribuímos a ela um Array Associativo contendo uma sequência de notas.
  • Logo em seguida invocamos a nossa função no passando-a como sendo a condição de um if (afinal ela já só pode retornar true ou false). Se ela retornar true a string: "Você zerou pelo menos uma disciplina!" será impressa, senão será impressa a string "Você não zerou nenhuma disciplina"

Beleza, mas e se no futuro eu esquecer que essa função recebe um array e eu passar para ela uma string?

Exemplo:

<?php

function temDisciplinaZerada($notas) {
    foreach($notas as $nota) {
        if($nota == 0) {
            return true;
        }
    }

    return false;
}

$notasDisciplinas = "5, 1, 0, 7";

if (temDisciplinaZerada($notasDisciplinas)) {
    echo "Você zerou pelo menos uma disciplina!";
} else {
    echo "Você não zerou nenhuma disciplina";
}

Ao executar isso você verá que o PHP vai lançar um "erro" no console

Warning: Invalid argument supplied for foreach() in /home/runner/CursoPHPAcampamentoDev/main.php on line 4
  1. Warning: O Warning não é bem um erro, ele é apenas um aviso de que tem algo errado com o seu código. Diferente do Fatal Error ele não para a execução do seu código, ele avisa e deixa a vida seguir.
  2. Invalid argument supplied for foreach(): Você forneceu ao foreach um argumento inválido, ou seja, ele esperava receber uma estrutura iterável mas você passou uma string.
  3. on line 4: O problema relatado está na linha 4 do seu código.

Mas como podemos resolver isso?

Em situação como essa o ideal é de fato lançar um Fatal Error, porque pode ter coisas no seu código que só deveriam ser executadas se tudo estiver correto. Para forçar o PHP a lançar um erro e de quebra ainda avisar ao usuário qual tipo de dados você espera você pode passar parâmetros tipados...

// ...
function temDisciplinaZerada(array $notas) {
// ...

... Dessa forma podemos informar que nossa função temDisciplinaZerada espera receber um array.

Se você executar agora, o erro vai ser diferente:

Fatal error: Uncaught TypeError: Argument 1 passed to temDisciplinaZerada() must be of the type array, string given, called in /home/runner/CursoPHPAcampamentoDev/main.php on line 15 and defined in /home/runner/CursoPHPAcampamentoDev/main.php:3
Stack trace:
#0 /home/runner/CursoPHPAcampamentoDev/main.php(15): temDisciplinaZerada('5, 1, 0, 7')
#1 {main}
  thrown in /home/runner/CursoPHPAcampamentoDev/main.php on line 3
exit status 255

Argument 1 passed to temDisciplinaZerada() must be of the type array, string given, called (O primeiro argumento passado para a função temDisciplinaZerada() deveria ser do tipo array, mas na realidade você passou uma string).

E ai, conseguiu pegar? Se teve dificuldade com alguma parte não fique triste, como eu sempre falo: "Saia um pouco, vai caminhar, jogar videogame, namorar, assistir um filme, etc... depois você volta e tenta novamente. E sempre que tiver dúvidas pode jogar ai nos comentários."

Desafio

Crie uma função que receba como parâmetro 1 array $palavras e devolva como return a palavra que tem mais letras. Se tiver mais de uma com a mesma quantidade de letras devolva só uma delas.

Até a próxima, escoteiro!!!