PHP use an enum for Filters
I have a class that allows filtering based on an option, I need a way to accept options and also reject invalid options.
In the past, I would reach for a switch statement, or more recently a match statement. But an enum is better suited for this task.
Using an array
public function filter($key, $value): static
{
$validOptions = [
'ids' => 'ids',
'includeArchived' => 'includeArchived',
'order' => 'order',
'page' => 'page',
'searchTerm' => 'searchTerm',
'summaryOnly' => 'summaryOnly',
'where' => 'where',
];
if (! in_array($key, $validOptions)) {
throw new InvalidArgumentException("Filter option '$key' is not valid.");
}
$this->queryString[$key] = $value;
return $this;
}
Using a switch statement:
public function filter($key, $value): static
{
switch ($key) {
case 'ids':
case 'includeArchived':
case 'order':
case 'page':
case 'searchTerm':
case 'summaryOnly':
case 'where':
$this->queryString[$key] = $value;
break;
default:
throw new InvalidArgumentException("Filter option '$key' is not valid.");
}
$this->queryString[$key] = $value;
return $this;
}
Using a match statement:
public function filter($key, $value): static
{
$this->queryString[$key] = match ($key) {
'ids', 'includeArchived', 'order', 'page', 'searchTerm', 'summaryOnly', 'where' => $this->queryString[$key] = $value,
default => throw new InvalidArgumentException("Filter option '$key' is not valid."),
};
return $this;
}
Using an enum
All the logic is stored in an enum class making the filter method smaller:
public function filter($key, $value): static
{
if (! ContactFilterOptions::isValid($key)) {
throw new InvalidArgumentException("Filter option '$key' is not valid.");
}
$this->queryString[$key] = $value;
return $this;
}
The advantage to this approach the enum is reusable, allowing to easily test the behaviour of both the enum and filter method.
The enum class looks like this:
enum ContactFilterOptions: string {
case IDS = 'ids';
case INCLUDEARCHIVED = 'includeArchived';
case ORDER = 'order';
case PAGE = 'page';
case SEARCHTERM = 'searchTerm';
case SUMMARYONLY = 'summaryOnly';
case WHERE = 'where';
public static function isValid(string $value): bool
{
$validValues = array_map(fn($case) => $case->value, self::cases());
return in_array($value, $validValues);
}
}
The isValid method is an easy way to determine if the string is in the lost of accepted values.
Tests
Adding tests to confirm for valid and invalid matches:
test('a valid option returns true', function() {
assertTrue(ContactFilterOptions::isValid('ids'));
assertTrue(ContactFilterOptions::isValid('includeArchived'));
assertTrue(ContactFilterOptions::isValid('order'));
assertTrue(ContactFilterOptions::isValid('page'));
assertTrue(ContactFilterOptions::isValid('searchTerm'));
assertTrue(ContactFilterOptions::isValid('summaryOnly'));
assertTrue(ContactFilterOptions::isValid('where'));
});
test('an invalid option returns false', function() {
assertFalse(ContactFilterOptions::isValid('bogus'));
});
Testing the filter method throws an exception:
test('invalid filter option throws exception', function(){
(new Contacts())->filter('bogus', 1);
})->throws(InvalidArgumentException::class, "Filter option 'bogus' is not valid.");
With this approach, your methods become smaller and easier to test.
Subscribe to my newsletter
Read articles from David Carr directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
David Carr
David Carr
Blogger at http://dcblog.dev.