PHP Enums tryFrom Method

I was recently working on a project where I was receiving data from an API that had a payment_type.

I was recently working on a project where I was receiving data from an API that had a payment_type. I converted the payment_type into the enum below:

enum PaymentType: string 
{
	case CREDIT_CARD = 'credit_card';
	case APPLE_PAY = 'apple_pay';
	case GOOGLE_PAY = 'google_pay';
	case PAYPAL = 'paypal';
	case SHOP_PAY = 'shop_pay';
}

Then, I use this enum in the data transfer object (DTO) to define the structure of the data I receive from the API.

However, the problem I was running into is the payment_type is not always in the response of the API data, so it could be null. In my DTO, I have a from method to build the object from the API response which looks like the following:

class OrderDto
{
	...
	public static function from(array $data): self {
		return new self(
			...
			payment_method: isset($data['payment_method']) ? PaymentType::from($data['payment_method']) : null,
		);
	}
}

I had to check if the payment_method is set too, because otherwise, a ValueError exception will be thrown.

This is where the tryFrom method comes in handy. If payment_method is null or is not a valid case for the enum, it will just return null without throwing an exception. So now, the DTO can be updated to the following which is much cleaner:

class OrderDto
{
	...
	public static function from(array $data): self {
		return new self(
			...
			payment_method: PaymentType::tryFrom($data['payment_method']),
		);
	}
}

Please note that this only works for backed enums in PHP 8.1+. In case you’re not familiar, a BackedEnum is one where each case has a value specified. So in the example above, the enum is a string-backed enum since it is defined with enum PaymentType: string.

This would not work for a standard PHP enum like the one below:

// Not a backed enum so does not include from and tryFrom methods.
enum PaymentType 
{
	case CREDIT_CARD;
	case APPLE_PAY;
	case GOOGLE_PAY;
	case PAYPAL;
	case SHOP_PAY;
}

If you found this tip helpful, I also have a similar one with the Carbon PHP make method. You can read that here.