diff --git a/src/Attributes/Field.php b/src/Attributes/Field.php index e4e764e..f29e8d6 100644 --- a/src/Attributes/Field.php +++ b/src/Attributes/Field.php @@ -373,6 +373,12 @@ public function exclude(): bool */ public function validate(mixed $value): bool { + if ($this->nullable && $value === null) { + // If the field is nullable and the value is null, we know it's valid. + // No need to call the validate() method further down. + return true; + } + $valueType = \get_debug_type($value); if ($this->phpType === $valueType) { @@ -380,8 +386,6 @@ public function validate(mixed $value): bool } elseif ($this->phpType === 'mixed') { // From a type perspective, mixed accepts anything. $valid = true; - } elseif ($this->nullable && $valueType === 'null') { - $valid = true; } elseif (is_object($value) || class_exists($this->phpType) || interface_exists($this->phpType)) { // For objects, do a type check and we're done. $valid = $value instanceof $this->phpType; diff --git a/tests/Records/NullablePointList.php b/tests/Records/NullablePointList.php new file mode 100644 index 0000000..431f32d --- /dev/null +++ b/tests/Records/NullablePointList.php @@ -0,0 +1,19 @@ +|null $points + */ + public function __construct( + #[SequenceField(arrayType: Point::class)] + public array|null $points = null, + ) { + } +} diff --git a/tests/Records/NullablePointListWithoutConstructor.php b/tests/Records/NullablePointListWithoutConstructor.php new file mode 100644 index 0000000..7ea36e3 --- /dev/null +++ b/tests/Records/NullablePointListWithoutConstructor.php @@ -0,0 +1,24 @@ + [ + 'data' => new NullablePointList(), + ]; + + $reflected = new ReflectionClass(NullablePointListWithoutConstructor::class); + $instance = $reflected->newInstanceWithoutConstructor(); + $reflected->getProperty('points')->setValue($instance, null); + yield 'nullable_list_without_constructor' => [ + 'data' => $instance, + ]; } public static function value_object_flatten_examples(): \Generator