# PHP Enumerations

Enumerations were added to PHP in PHP 8.1 so I decided to give them a try, and I quite like them.

Here’s the most basic form

```php
enum MaritalStatus {
  case Single;
  case Married;
  case Divorced;
  case Separated;
  case Widowed;
}
```

So now you can do

```php
$employeeMaritalStatus = MaritalStatus::Married;
```

and

```php
if ($employeeMaritalStatus == MaritalStatus::Married) {
  echo 'Employee is married';
}
```

You can’t do

```php
echo $employeeMaritalStatus;
```

because an enum isn’t a string, and it’s not automatically convertible into a string, but you can do

```php
echo $employeeMaritalStatus->name;
```

which will get you a string value like “Married”, “Single”, etc.

The first thing you might want to do is produce a human-readable display version of that, e.g. “Divorced/Civil Partnership Dissolved” instead of “Divorced”.

That’s called a *backed enumeration*, so it becomes this

```php
enum MaritalStatus: string {
  case Single = 'Single';
  case Married = 'Married/Civil Partner';
  case Divorced = 'Divorced/Civil Partnership Dissolved';
  case Separated = 'Separated';
  case Widowed = 'Widowed/Surviving Civil Partner';
}
```

You still can’t do

```php
echo $employeeMaritalStatus;
```

But you can now do

```php
echo $employeeMaritalStatus->name;
```

which will get you “Married”, or

```php
echo $employeeMaritalStatus->value;
```

which gets you “Married/Civil Partner”;

The next thing you might want to do is convert a string to an enum value. Say if an API has returned a string value “Married”, you want to be able to convert that to a proper enum in your PHP object.

So we add a couple of static methods

```php
enum MaritalStatus: string {
  case Single = 'Single';
  case Married = 'Married/Civil Partner';
  case Divorced = 'Divorced/Civil Partnership Dissolved';
  case Separated = 'Separated';
  case Widowed = 'Widowed/Surviving Civil Partner';

  public static function fromString(string $name): MaritalStatus {
    try {
      return self::{$name};
    } catch (\Error) {
      throw new \ValueError('"'.$name.'" is not a valid value for '.self::class);
    }
  }

  public static function fromNullableString(?string $name): ?MaritalStatus {
    return $name === null ? null : self::fromString($name);
  }
}
```

So now you can do

```php
$myString = 'Married';
$employeeMaritalStatus = MaritalStatus::fromString($myString);
```

The next problem we need to solve is a problem I ran into when serializing objects containing the enum.

Say I've got a variable called ```$employee``` that contains a property ```$maritalStatus``` that I want to pass into an API

I do

```php
$json = json_encode($employee);
```

to convert it to JSON to send to the API. If the marital status is “Single” or “Separated” it works, but if I send a “Married” one it falls over. The API complains that that’s not a valid MaritalStatus.

What’s happening is that by default, when you do json_encode on a backed enum, it converts it to the *string* value, not the enum value. So for a Single one, the API is receiving this

```json
{
  "employeeId": 2645,
  "forename": "Jane",
  "surname": "Jones",
  "maritalStatus": "Single"
}
```

That’s fine because for a Single one, the enum and its string equivalent are identical, but for a Married one we’re sending

```json
{
  "employeeId": 2645,
  "forename": "Jane",
  "surname": "Jones",
  "maritalStatus": "Married/Civil Partner"
}
```

The API doesn’t recognise “Married/Civil Partner” as a valid status.

So we have to control the serialisation behaviour ourselves. You implement the JsonSerializable interface.

```php
enum MaritalStatus: string implements \JsonSerializable {
  case Single = 'Single';
  case Married = 'Married/Civil Partner';
  case Divorced = 'Divorced/Civil Partnership Dissolved';
  case Separated = 'Separated';
  case Widowed = 'Widowed/Surviving Civil Partner';

  public static function fromString(string $name): MaritalStatus {
    try {
      return self::{$name};
    } catch (\Error) {
      throw new \ValueError('"'.$name.'" is not a valid value for '.self::class);
    }
  }

  public static function fromNullableString(?string $name): ?MaritalStatus {
    return $name === null ? null : self::fromString($name);
  }

  public function jsonSerialize(): string {
    return $this->name;
  }
}
```

So now a Married one gets converted to JSON as “Married” instead of “Married/Civil Partner”. The API receives this

```json
{
  "employeeId": 2645,
  "forename": "Jane",
  "surname": "Jones"
  "maritalStatus": "Married"
}
```

and it’s all happy.

Then to take it a step further. The ```fromString()``` and ```fromNullableString()``` both return a value of ```MaritalStatus```, i.e. of the type that we’re currently in. Where that’s the case, you can have a return type of ```self```, i.e.

```php
enum MaritalStatus: string implements \JsonSerializable {
  case Single = 'Single';
  case Married = 'Married/Civil Partner';
  case Divorced = 'Divorced/Civil Partnership Dissolved';
  case Separated = 'Separated';
  case Widowed = 'Widowed/Surviving Civil Partner';

  public static function fromString(string $name): self {
    try {
      return self::{$name};
    } catch (\Error) {
      throw new \ValueError('"'.$name.'" is not a valid value for '.self::class);
    }
  }

  public static function fromNullableString(?string $name): ?self {
    return $name === null ? null : self::fromString($name);
  }

  public function jsonSerialize(): string {
    return $this->name;
  }
}
```

So now those three methods don’t have anything in them that refers to a specific enum type. They will work for *any* enum type. So you’d think that’s an obvious candidate for an abstract base class, but you can’t do inheritance on enums.

So there’s a thing called a *Trait* in PHP which I’d heard of but never actually looked into. It’s a bit like a quick and dirty base class. Or like one of those classes that’s got nothing but static methods, except the methods don’t have to be static.

```php
trait Multiplying {
  public function multiplyBy2() {
    return $this->myVal * 2;
  }

  public function multiplyBy4() {
    return $this->myVal * 4;
  }
}
```

So once you’ve defined it, any class that uses that trait gets those methods.

```php
class MyClass {
  use Multiplying;

  public int $myVal;
}

$myObject = new MyClass();
$myObject->myVal = 5;

echo $myObject->multiplyBy2();
echo '<br>';
echo $myObject->multiplyBy4();
```

That’s a rubbish example, but you get the idea.

So if we define a trait like this

```php
trait CommonEnumMethods {
  public static function fromString(string $name): self {
    try {
      return self::{$name};
    } catch (\Error $e) {
      throw new \ValueError('"'.$name.'" is not a valid value for '.self::class);
    }
  }

  public static function fromNullableString(?string $name): ?self {
    return $name === null ? null : self::fromString($name);
  }

  public function jsonSerialize(): string {
    return $this->name;
  }
}
```

Our actual enum can look like this

```php
enum MaritalStatus: string implements \JsonSerializable {
  use CommonEnumMethods;

  case Single = 'Single';
  case Married = 'Married/Civil Partner';
  case Divorced = 'Divorced/Civil Partnership Dissolved';
  case Separated = 'Separated';
  case Widowed = 'Widowed/Surviving Civil Partner';
}
```

And it gets all the methods from the trait. So now all new enums that we add can just use the trait to get all the functionality that we need.
