Skip to content

Latest commit

 

History

History
57 lines (48 loc) · 1.62 KB

File metadata and controls

57 lines (48 loc) · 1.62 KB

Use default for unexpected values

There are situations where you're deserializing data from a third party that doesn't have an API documentation or one that can't keep a backwards compatibility promise. One such case is when a third party uses an enum and you expect that new enum values might get added in the future by them. For example, imagine this structure:

enum CardType: string 
{
	case CLUBS = 'clubs';
	case DIAMONDS = 'diamonds';
	case HEARTS = 'hearts'; 
	case SPADES = 'spades';	
}

readonly class Card {
	public function __construct(
		public CardType $type,
		public string $value,
	) {}
}

If you get an unexpected value for type, you'll get an exception:

// UnexpectedEnumValueException: Expected one of [clubs, diamonds, hearts, spades], but got 'joker'
$adapter->deserialize('{"type": "joker"}');

So if you suspect that might happen, add a default value you wish to use (anything) and a #[UseDefaultForUnexpected] attribute:

readonly class Card {
	public function __construct(
		#[UseDefaultForUnexpected]
		public CardType $type = null,
		// Can be any other valid default value
		#[UseDefaultForUnexpected]
		public CardType $type2 = CardType::SPADES,
	) {}
}

Whenever that happens, a default value will be used instead. Optionally, you can also log such cases:

$serializer = (new SerializerBuilder())
	->reportUnexpectedDefault(function (BoundClassProperty $property, UnexpectedValueException $e) {
		$log->warning("Serializer used a default for unexpected value: {$e->getMessage()}", [
			'property' => $property->serializedName(),
			'exception' => $e,
		]);
	})
	->build();