diff --git a/core/lib/Drupal/Component/Utility/FilterArray.php b/core/lib/Drupal/Component/Utility/FilterArray.php
new file mode 100644
index 0000000000000000000000000000000000000000..172348df11638edc41479ee6edf787f5b32e6bc3
--- /dev/null
+++ b/core/lib/Drupal/Component/Utility/FilterArray.php
@@ -0,0 +1,31 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Component\Utility;
+
+/**
+ * Provides methods to filter arrays.
+ *
+ * @ingroup utility
+ */
+class FilterArray {
+
+  /**
+   * Removes empty strings from an array.
+   *
+   * This method removes all empty strings from the input array. This is
+   * particularly useful to preserve 0 whilst filtering other falsy values. The
+   * values are first cast to a string before comparison.
+   *
+   * @param array $value
+   *   The array to filter.
+   *
+   * @return array
+   *   The filtered array.
+   */
+  public static function removeEmptyStrings(array $value): array {
+    return array_filter($value, static fn ($item) => (string) $item !== '');
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Datetime/Element/Datelist.php b/core/lib/Drupal/Core/Datetime/Element/Datelist.php
index 1b918131a8707327bed6305cdfc6563b3f62e75f..c94ecfa58c3f56e7722031a1d00b9ccc405d6910 100644
--- a/core/lib/Drupal/Core/Datetime/Element/Datelist.php
+++ b/core/lib/Drupal/Core/Datetime/Element/Datelist.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Core\Datetime\Element;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\Variable;
 use Drupal\Core\Datetime\DateHelper;
@@ -345,7 +346,7 @@ protected static function checkEmptyInputs($input, $parts) {
     // \Drupal\Core\Datetime\Element\Datelist::valueCallback().
     unset($input['object']);
     // Filters out empty array values, any valid value would have a string length.
-    $filtered_input = array_filter($input, 'strlen');
+    $filtered_input = FilterArray::removeEmptyStrings($input);
     return array_diff($parts, array_keys($filtered_input));
   }
 
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
index ee648a50f86f98de5478824bfd56e2f4839a4407..9454862ff979225a37f998a25b191a381624f18d 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/ItemList.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Core\TypedData\Plugin\DataType;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\TypedData\Attribute\DataType;
 use Drupal\Core\TypedData\ComplexDataInterface;
@@ -92,7 +93,7 @@ public function getString() {
       $strings[] = $item->getString();
     }
     // Remove any empty strings resulting from empty items.
-    return implode(', ', array_filter($strings, 'mb_strlen'));
+    return implode(', ', FilterArray::removeEmptyStrings($strings));
   }
 
   /**
diff --git a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
index e08e9312e0c7760d6dc5e6b8569e42e707259d77..16aaa68fdc448711c8a1e842b097d92b6b7569b5 100644
--- a/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
+++ b/core/lib/Drupal/Core/TypedData/Plugin/DataType/Map.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Core\TypedData\Plugin\DataType;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\TypedData\Attribute\DataType;
 use Drupal\Core\TypedData\ComplexDataInterface;
@@ -106,7 +107,7 @@ public function getString() {
       $strings[] = $property->getString();
     }
     // Remove any empty strings resulting from empty items.
-    return implode(', ', array_filter($strings, 'mb_strlen'));
+    return implode(', ', FilterArray::removeEmptyStrings($strings));
   }
 
   /**
diff --git a/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceOptionTranslation.php b/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceOptionTranslation.php
index 6342c027de09f03cad039d6949b55d78f329595c..9ddca549026558f18605f811b4ae86903d2a4b71 100644
--- a/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceOptionTranslation.php
+++ b/core/modules/field/src/Plugin/migrate/process/d6/FieldInstanceOptionTranslation.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\field\Plugin\migrate\process\d6;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\migrate\Attribute\MigrateProcess;
 use Drupal\migrate\MigrateExecutableInterface;
 use Drupal\migrate\ProcessPluginBase;
@@ -27,7 +28,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
     if (isset($global_settings['allowed_values'])) {
       $list = explode("\n", $global_settings['allowed_values']);
       $list = array_map('trim', $list);
-      $list = array_filter($list, 'strlen');
+      $list = FilterArray::removeEmptyStrings($list);
       switch ($field_type) {
         case 'boolean';
           $option = preg_replace('/^option_/', '', $row->getSourceProperty('property'));
diff --git a/core/modules/field/src/Plugin/migrate/process/d6/FieldOptionTranslation.php b/core/modules/field/src/Plugin/migrate/process/d6/FieldOptionTranslation.php
index 6c6cf100fa9307c5232540d46aa99d6db46fca92..94842bda74e03f546437b5957a8437da2dd516b4 100644
--- a/core/modules/field/src/Plugin/migrate/process/d6/FieldOptionTranslation.php
+++ b/core/modules/field/src/Plugin/migrate/process/d6/FieldOptionTranslation.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\field\Plugin\migrate\process\d6;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\migrate\Attribute\MigrateProcess;
 use Drupal\migrate\MigrateExecutableInterface;
 use Drupal\migrate\ProcessPluginBase;
@@ -29,7 +30,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
     if (isset($global_settings['allowed_values'])) {
       $list = explode("\n", $global_settings['allowed_values']);
       $list = array_map('trim', $list);
-      $list = array_filter($list, 'strlen');
+      $list = FilterArray::removeEmptyStrings($list);
       switch ($field_type) {
         case 'list_string':
         case 'list_integer':
diff --git a/core/modules/field/src/Plugin/migrate/process/d6/FieldSettings.php b/core/modules/field/src/Plugin/migrate/process/d6/FieldSettings.php
index ce247d025d993036cc99833f6a3815b6333bf4cc..ffdb2e6fcb57039a17b013934f70777ca7e9b2b7 100644
--- a/core/modules/field/src/Plugin/migrate/process/d6/FieldSettings.php
+++ b/core/modules/field/src/Plugin/migrate/process/d6/FieldSettings.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\field\Plugin\migrate\process\d6;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\migrate\Attribute\MigrateProcess;
 use Drupal\migrate\MigrateExecutableInterface;
 use Drupal\migrate\ProcessPluginBase;
@@ -50,7 +51,7 @@ public function getSettings($field_type, $global_settings, $original_field_type
     if (isset($global_settings['allowed_values'])) {
       $list = explode("\n", $global_settings['allowed_values']);
       $list = array_map('trim', $list);
-      $list = array_filter($list, 'strlen');
+      $list = FilterArray::removeEmptyStrings($list);
       switch ($field_type) {
         case 'list_string':
         case 'list_integer':
diff --git a/core/modules/sqlite/src/Driver/Database/sqlite/Connection.php b/core/modules/sqlite/src/Driver/Database/sqlite/Connection.php
index 8e6d06b6fe2f2fbf55bfc2b489868b429a63458a..53c2fa0c1fe0f45dd57ffb10e5be232d11434234 100644
--- a/core/modules/sqlite/src/Driver/Database/sqlite/Connection.php
+++ b/core/modules/sqlite/src/Driver/Database/sqlite/Connection.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\sqlite\Driver\Database\sqlite;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\Core\Database\Connection as DatabaseConnection;
 use Drupal\Core\Database\DatabaseNotFoundException;
 use Drupal\Core\Database\ExceptionHandler;
@@ -246,7 +247,7 @@ public static function sqlFunctionGreatest() {
    */
   public static function sqlFunctionLeast() {
     // Remove all NULL, FALSE and empty strings values but leaves 0 (zero) values.
-    $values = array_filter(func_get_args(), 'strlen');
+    $values = FilterArray::removeEmptyStrings(func_get_args());
 
     return count($values) < 1 ? NULL : min($values);
   }
diff --git a/core/modules/user/src/Plugin/migrate/process/d6/ProfileFieldOptionTranslation.php b/core/modules/user/src/Plugin/migrate/process/d6/ProfileFieldOptionTranslation.php
index fd7aea36bce7b23c3fe993540f6aefc2544a74b0..1cd4efff49b9860222168399a4d9a083fdec37af 100644
--- a/core/modules/user/src/Plugin/migrate/process/d6/ProfileFieldOptionTranslation.php
+++ b/core/modules/user/src/Plugin/migrate/process/d6/ProfileFieldOptionTranslation.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\user\Plugin\migrate\process\d6;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\migrate\Attribute\MigrateProcess;
 use Drupal\migrate\MigrateExecutableInterface;
 use Drupal\migrate\ProcessPluginBase;
@@ -27,7 +28,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
       $allowed_values = [];
       $list = explode("\n", $translation);
       $list = array_map('trim', $list);
-      $list = array_filter($list, 'strlen');
+      $list = FilterArray::removeEmptyStrings($list);
       if ($field_type === 'list_string') {
         foreach ($list as $value) {
           $allowed_values[] = ['label' => $value];
diff --git a/core/modules/views/src/Plugin/views/HandlerBase.php b/core/modules/views/src/Plugin/views/HandlerBase.php
index 3c576d13d520f108d76780d110383dbd36dea2b7..583efd832c4c2bb84031734e7d0f3cbb47557773 100644
--- a/core/modules/views/src/Plugin/views/HandlerBase.php
+++ b/core/modules/views/src/Plugin/views/HandlerBase.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\views\Plugin\views;
 
+use Drupal\Component\Utility\FilterArray;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
@@ -758,7 +759,7 @@ public static function breakString($str, $force_int = FALSE) {
     // Filter any empty matches (Like from '++' in a string) and reset the
     // array keys. 'strlen' is used as the filter callback so we do not lose
     // 0 values (would otherwise evaluate == FALSE).
-    $value = array_values(array_filter($value, 'strlen'));
+    $value = array_values(FilterArray::removeEmptyStrings($value));
 
     if ($force_int) {
       $value = array_map('intval', $value);
diff --git a/core/tests/Drupal/Tests/Component/Utility/FilterArrayTest.php b/core/tests/Drupal/Tests/Component/Utility/FilterArrayTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..289b19bfe824ce9a9ab6f503ac03fdd13a452cd6
--- /dev/null
+++ b/core/tests/Drupal/Tests/Component/Utility/FilterArrayTest.php
@@ -0,0 +1,62 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\Component\Utility;
+
+use Drupal\Component\Utility\FilterArray;
+use PHPUnit\Framework\TestCase;
+
+/**
+ * Test filter array functions.
+ *
+ * @group Utility
+ *
+ * @coversDefaultClass \Drupal\Component\Utility\FilterArray
+ */
+class FilterArrayTest extends TestCase {
+
+  /**
+   * Tests removing empty strings.
+   *
+   * @dataProvider providerRemoveEmptyStrings
+   * @covers ::removeEmptyStrings
+   */
+  public function testRemoveEmptyStrings(array $values, array $expected): void {
+    $this->assertEquals($expected, array_values(FilterArray::removeEmptyStrings($values)));
+  }
+
+  /**
+   * Data provider for testRemoveEmptyStrings().
+   *
+   * @see testRemoveEmptyStrings()
+   */
+  public static function providerRemoveEmptyStrings(): \Generator {
+    yield 'strings' => [
+      ['', ' ', '0', 'true', 'false'],
+      [' ', '0', 'true', 'false'],
+    ];
+    yield 'integers' => [
+      [-1, 0, 1],
+      [-1, 0, 1],
+    ];
+    yield 'null, true, false' => [
+      [NULL, TRUE, FALSE],
+      [TRUE],
+    ];
+
+    $stringable = new class implements \Stringable {
+
+      public function __toString(): string {
+        return 'foo';
+      }
+
+    };
+
+    yield 'non-scalar' => [
+      [new $stringable()],
+      [new $stringable()],
+    ];
+  }
+
+}