É basicamente uma função que retorna um objeto. Mas é feito de uma maneira, na minha opinião, desnecessariamente complicada (mais detalhes abaixo). Mas vamos por partes...
Função anônima
Primeiro o código cria uma função anônima - no caso, function ($name, $age)
indica que ela recebe dois parâmetros (o nome e a idade).
Mas em PHP funções anônimas funcionam como closures (ver mais aqui e aqui), ou seja, ela pode "capturar" variáveis de um escopo externo. No caso, o use ($friend)
indica que a função vai usar o valor da variável $friend
, que foi declarada fora da função.
Esse ponto é importante: não importa se mudarmos o valor de $friend
depois, a função continua usando o valor que a variável tinha no momento em que a closure foi criada. Por exemplo, se eu fizer:
$person = $getPerson("Gabriel", 19);
echo ($person->saudation()). "\n";
$friend = "Bob";
$person = $getPerson("Fulano", 42);
echo ($person->saudation()). "\n";
A saída será:
Olá, meu nome é Gabriel, tenho 19 anos de idade
e sou amigo da Allyce
Olá, meu nome é Fulano, tenho 42 anos de idade
e sou amigo da Allyce
Pois quando a função foi criada, ela usa o valor que $friend
tinha naquele momento.
Como curiosidade, se eu quisesse que uma alteração no valor de $friend
se refletisse dentro da closure (ou seja, no código acima o segundo caso imprimisse "Bob" em vez de "Allyce"), teria que mudar para use (&$friend)
(o uso de &
faz com que agora ele use uma referência).
Classe anônima
Dentro da função, é criada uma classe anônima, e uma instância desta é retornada. Ela basicamente usa o nome e idade que foram passados como argumentos, e a variável $friend
declarada fora da função, como já explicado acima.
Ou seja, ao fazer $getPerson("Gabriel", 19);
, a função retornará uma classe usando $name
igual a "Gabriel", $age
igual a 19
e $friend
será "Allyce", que foi definido anteriormente, quando a função foi criada. Se eu quiser criar outra instância com dados diferentes, basta chamar a função com outros parâmetros - por exemplo, $getPerson("Fulano", 42)
- o $friend
continua sendo "Allyce", como já explicado.
Precisa ser assim?
Como eu disse no início, acho que o código é desnecessariamente complicado. Acho que funções e classes anônimas têm o seu uso (ver aqui e aqui), mas este caso não me parece ser um deles.
Seria mais simples criar uma classe e pronto:
class Person {
function __construct(private $name, private $age, private $friend) {
}
public function saudation(): string {
return <<<LABEL
Olá, meu nome é {$this->name}, tenho {$this->age} anos de idade
e sou amigo da {$this->friend}
LABEL;
}
}
$person = new Person("Gabriel", 19, "Allyce");
echo ($person->saudation()), "\n";
"Ah, mas agora não tem mais o valor default de $friend
, tenho que passar como parâmetro toda hora."
Sim, mas será que fazia sentido este comportamento do código original? Se todas as pessoas só tem o mesmo amigo, vc pode usar um valor default para ele, como por exemplo:
function __construct(private $name, private $age, private $friend = null) {
if ($this->friend == null) {
$this->friend = "Allyce";
}
}
Ou simplesmente não coloque $friend
como parâmetro do construtor, e inicialize-o sempre com o mesmo valor. Não vejo muito ganho da forma que estava no código original.