Property Hooks no PHP 8.4
Tags: php
Published: 2024-04-20 04:05:08

## Property Hooks

Os property hooks são funções que controlam como uma propriedade é setada ou como seu valor é lido. Esta funcionalidade é comum em linguagens orientadas a objeto, mas, até então, o PHP não oferecia suporte nativo. Tradicionalmente, a alternativa era recorrer a funções getter/setter ou fazer uso de métodos mágicos. Contudo, por  35 votos a 1, a [RFC dos property hooks](https://wiki.php.net/rfc/property-hooks) foi aprovada para a próxima versão do PHP. Este artigo explora as abordagens atuais e como os property hooks podem nos ajudar na validação dos dados.



### Getter e Setter
Nesta abordagem, definimos a propriedade email como privada e a só pode ser acessada através da função getEmail/setEmail. Como queremos validar o email, incluímos essa validação no set.


```PHP
class User
{
    private string $email;

    public function getEmail(): string
    {
        return $this->email;
    }

    public function setEmail(string $email): void
    {
        if (! filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new Exception('Invalid email');
        }
        $this->email = $email;
    }
}

$user = new User();
$user->setEmail('valido@hotmail.com');
echo $user->getEmail(); //valido@hotmail.com
```
Essa abordagem é bastante comum, mas é muito verbosa e não funciona bem quando trabalhamos com algum ORM.

### Propriedades mágicas 
Aqui quem não tá acostumado com a ideia dos métodos mágicos do PHP fica maluco.

A ideia é que sempre que uma propriedade for acessada, vai chamar o método __get e passar o nome da propriedade como parâmetro.
Quando for definir alguma propriedade o método __set é executado, passando o nome da propriedade e o valor.

Não preciso dizer que é fácil ficar confuso quando temos muitas prioridades já que uma única função lida com todas as propriedades da classe.



```PHP
class User
{
    private string $properties = [];

    public function __get($property)
    {
        return $this->properties[$property] ?? null
    }

    public function __set($property, $value)
    {
        switch ($property) {
            case 'email':
                if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    throw new Exception('Email inválido');
                }
                $this->properties['email'] = $value;
                break;
            case 'name':
                $this->properties['name'] = $value;
                break;
        }
    }
}
//

$user = new User();
$user->name = 'John Doe';
$user->email = 'invalido'; //Exception: Email inválido
echo $user->getEmail();
```
Normalmente essa é a solução adotadas por ORMs, porque as propriedades não precisam de fato existirem no objeto e tudo é passado para os métodos mágicos.

### property hooks
Com a chegada do properties hooks, a definição de como uma propriedade vai ser acessada fica no local da declaração da propriedade, separando melhor as responsabilidades e adotando uma abordagem um pouco mais declarativa.


**Exemplo de set**
```PHP
class User
{
    public string $name;
    public string $email {
         set {
            if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
                throw new Exception('Email inválido');
            }
            $this->_email = $value;
        }
    }
}
//

$user = new User();
$user->name = 'John Doe';
$user->email = 'invalid'; //Exception: Email inválido
echo $user->getEmail();
```

**Exemplo de get**
```PHP
class User
{

    public string $fullName {
        get {
            return "$this->firstName $this->lastName";
        }
    }

    public function __construct(private readonly string $firstName, private readonly string $lastName)
    {
    }


}
//

$user = new User("Roberto", "Murari");
echo $user->fullName; //Roberto Murari
```

### Conclusão 
Os property hooks prometem transformar a forma como gerenciamos e acessamos propriedades em classes PHP, oferecendo uma sintaxe mais limpa e um controle mais fino. Não vem como substituição aos métodos mágicos ou uso de funções getter/setter mas uma nova alternativa que podemos utilizar onde fizer mais sentido.