diff --git a/CHANGELOG.md b/CHANGELOG.md
index d4bbf52..18618bd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,9 @@
 # Yii Hydrator Change Log
 
-## 1.0.1 under development
+## 1.1.0 under development
 
-- no changes in this release.
+- New #74: Add option `castEmptyStringToNull` to `PhpNativeTypeCaster` (@vjik)
 
 ## 1.0.0 January 29, 2024
 
-- Initial release.
\ No newline at end of file
+- Initial release.
diff --git a/src/TypeCaster/PhpNativeTypeCaster.php b/src/TypeCaster/PhpNativeTypeCaster.php
index 2d65a24..d7127c3 100644
--- a/src/TypeCaster/PhpNativeTypeCaster.php
+++ b/src/TypeCaster/PhpNativeTypeCaster.php
@@ -23,6 +23,11 @@
  */
 final class PhpNativeTypeCaster implements TypeCasterInterface
 {
+    public function __construct(
+        public bool $castEmptyStringToNull = false,
+    ) {
+    }
+
     public function cast(mixed $value, TypeCastContext $context): Result
     {
         $type = $context->getReflectionType();
@@ -49,8 +54,12 @@ public function cast(mixed $value, TypeCastContext $context): Result
          * - when pass `"42"` to `int|string` type, `string` will be used.
          */
         foreach ($types as $t) {
-            if ($value === null && $t->allowsNull()) {
-                return Result::success(null);
+            if ($t->allowsNull()) {
+                if ($value === null
+                    || ($this->castEmptyStringToNull && $value === '')
+                ) {
+                    return Result::success(null);
+                }
             }
             if (!$t->isBuiltin()) {
                 continue;
@@ -108,8 +117,7 @@ public function cast(mixed $value, TypeCastContext $context): Result
                         return Result::success((int) $value);
                     }
                     if ($value instanceof Stringable || is_string($value)) {
-                        $value = NumericHelper::normalize($value);
-                        return Result::success($t->allowsNull() && $value === '' ? null : (int) $value);
+                        return Result::success((int) NumericHelper::normalize($value));
                     }
                     break;
 
@@ -118,15 +126,11 @@ public function cast(mixed $value, TypeCastContext $context): Result
                         return Result::success((float) $value);
                     }
                     if ($value instanceof Stringable || is_string($value)) {
-                        $value = NumericHelper::normalize($value);
-                        return Result::success($t->allowsNull() && $value === '' ? null : (float) $value);
+                        return Result::success((float) NumericHelper::normalize($value));
                     }
                     break;
 
                 case 'bool':
-                    if ($t->allowsNull() && $value === '') {
-                        return Result::success(null);
-                    }
                     if (is_scalar($value) || $value === null || is_array($value) || is_object($value)) {
                         return Result::success((bool) $value);
                     }
diff --git a/tests/TypeCaster/PhpNativeTypeCasterTest.php b/tests/TypeCaster/PhpNativeTypeCasterTest.php
index 9e282aa..33e7689 100644
--- a/tests/TypeCaster/PhpNativeTypeCasterTest.php
+++ b/tests/TypeCaster/PhpNativeTypeCasterTest.php
@@ -26,7 +26,7 @@ public function dataBase(): array
                 static fn(float $a) => null,
             ],
             'empty string to int|null' => [
-                Result::success(null),
+                Result::success(0),
                 '',
                 static fn(?int $a) => null,
             ],
@@ -36,15 +36,20 @@ public function dataBase(): array
                 static fn(?string $a) => null,
             ],
             'empty string to float|null' => [
-                Result::success(null),
+                Result::success(0.0),
                 '',
                 static fn(?float $a) => null,
             ],
             'empty string to bool|null' => [
-                Result::success(null),
+                Result::success(false),
                 '',
                 static fn(?bool $a) => null,
             ],
+            'empty string to array|null' => [
+                Result::fail(),
+                '',
+                static fn(?array $a) => null,
+            ],
         ];
     }
 
@@ -61,4 +66,50 @@ public function testBase(Result $expected, mixed $value, Closure $closure): void
         $this->assertSame($expected->isResolved(), $result->isResolved());
         $this->assertSame($expected->getValue(), $result->getValue());
     }
+
+    public function dataWithCastEmptyStringToNull(): array
+    {
+
+        return [
+            'empty string to int|null' => [
+                Result::success(null),
+                '',
+                static fn(?int $a) => null,
+            ],
+            'empty string to string|null' => [
+                Result::success(null),
+                '',
+                static fn(?string $a) => null,
+            ],
+            'empty string to float|null' => [
+                Result::success(null),
+                '',
+                static fn(?float $a) => null,
+            ],
+            'empty string to bool|null' => [
+                Result::success(null),
+                '',
+                static fn(?bool $a) => null,
+            ],
+            'empty string to array|null' => [
+                Result::success(null),
+                '',
+                static fn(?array $a) => null,
+            ],
+        ];
+    }
+
+    /**
+     * @dataProvider dataWithCastEmptyStringToNull
+     */
+    public function testWithCastEmptyStringToNull(Result $expected, mixed $value, Closure $closure): void
+    {
+        $typeCaster = new PhpNativeTypeCaster(castEmptyStringToNull: true);
+        $context = TestHelper::createTypeCastContext($closure);
+
+        $result = $typeCaster->cast($value, $context);
+
+        $this->assertSame($expected->isResolved(), $result->isResolved());
+        $this->assertSame($expected->getValue(), $result->getValue());
+    }
 }