Skip to content

Instantly share code, notes, and snippets.

@rafaelfelipesantos
Created December 13, 2020 21:56
Show Gist options
  • Save rafaelfelipesantos/22a87031275b0bb405df03db764c9e7a to your computer and use it in GitHub Desktop.
Save rafaelfelipesantos/22a87031275b0bb405df03db764c9e7a to your computer and use it in GitHub Desktop.
Alternativa elegante ao Enum em PHP sem usar constants
<?php
// Vamos ao cenário hipotético:
interface PaymentStatus
{
const PAID = 1;
const CANCELED = 2;
// Isso soa familiar?
}
// Tudo bem, você não pode reescrever o valor de constants que pertencem à interfaces no PHP,
// mas você realmente quer um valor INTEGER ou um STATUS VÁLIDO que possa CONFIAR?
// Nem quero entrar no mérito do Pattern State, mas nesse gist quero apenas mostrar que existe vida além
// das constants. Ah, se você pensou em Reflection, pode ir tirando o seu cavalinho da chuva rs.
// INTEGER, STATUS VÁLIDO, CONFIAR, CONFIANÇA, OOP...
// Ooooh, temos um Sherlock Holmes aqui.
// Sigam-me os bons:
interface PaymentStatuses
{
public function equals(PaymentStatuses $other): bool;
}
trait Compare
{
public function equals(PaymentStatuses $other): bool
{
return $other instanceof $this;
}
}
final class Paid implements PaymentStatuses
{
use Compare;
}
final class Canceled implements PaymentStatuses
{
use Compare;
}
final class PaymentStatus
{
private function __construct() {}
public static function PAID(): PaymentStatuses
{
return new Paid();
}
public static function CANCELED(): PaymentStatuses
{
return new Canceled();
}
// ...
}
// Agora vamos ao que interessa:
class PaymentStatusTest extends TestCase
{
public function testShouldCreateAValidStatus()
{
$paid = PaymentStatus::PAID();
$this->assertInstanceOf(PaymentStatuses::class, $paid);
// Por um segundo, esqueça o instanceOf e imagine que usou constants do tipo INTEGER.
// Sim, você compararia dois números. Não é esse o valor da constant?
}
public function testShouldValidadeEqualityBetweenStatuses()
{
$paid = PaymentStatus::PAID();
$this->assertTrue($paid->equals(clone $paid));
// Tudo bem, 1 poder até ser igual à 1, mas a classe Client espera um status válido ou um integer?
}
public function testShouldValidadeDiffBetweenStatuses()
{
$paid = PaymentStatus::PAID();
$this->assertFalse($paid->equals(PaymentStatus::CANCELED()));
// Novamente, 1 !== 2.
// Imagine usar Reclection só pra GARANTIR um status válido dentre os status da sua aplicação.
// Outro ponto, o que me impede de chamar PaymentStatus::AQUI_EH_BR; Entendeu?
}
}
// Quando eu digo um Client que espere um status válido, estou falando sobre confiança:
final class Bill
{
private PaymentStatuses $status;
public function __construct(PaymentStatuses $status)
{
$this->status = $status;
// O que é que eu vou fazer com um INT aqui?
// E quando o status for alterado, só que antes disso você precisa garantir o fluxo padrão
// para que seja alterado. E sim, nesse caso o pattern state é muito bem vindo.
}
}
// Bom, espero que tenha entendido a problemática das constants para guardar valores referentes à estados da aplicação.
// O Rafael do futuro tem o hábito de esquecer as coisas que ele aprende no passado. Então, quando esse dia chegar e
// for pesquisar no Google, talvez caia aqui!
// Forte abraço :)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment