From cbcdb8b2d4282b223a4fe88df13e19e85347d3cc Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Mon, 7 Feb 2022 11:26:28 +0000
Subject: [PATCH] Issue #3164210 by jungle, sylus, Akhildev.cs, dww: Refactor
 array_merge() usage in loops as possible for performance

---
 .../Core/Authentication/AuthenticationCollector.php      | 5 +----
 core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php    | 5 +----
 core/lib/Drupal/Core/Config/ConfigManager.php            | 4 ++--
 core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php  | 8 +++++---
 .../Drupal/Core/Entity/EntityAccessControlHandler.php    | 8 +++++---
 core/lib/Drupal/Core/Extension/ModuleHandler.php         | 3 ++-
 core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php   | 7 +------
 core/lib/Drupal/Core/Logger/LoggerChannel.php            | 7 +------
 .../Drupal/Core/PathProcessor/PathProcessorManager.php   | 7 +------
 .../Drupal/Core/RouteProcessor/RouteProcessorManager.php | 7 +------
 .../Drupal/Core/StringTranslation/TranslationManager.php | 7 +------
 .../src/Controller/ConfigTranslationMapperList.php       | 4 +---
 .../EntityReference/EntityReferenceAdminTest.php         | 4 +++-
 .../jsonapi/src/Routing/ReadOnlyModeMethodFilter.php     | 3 ++-
 core/modules/locale/locale.bulk.inc                      | 3 ++-
 .../src/RegisterEntityResolversCompilerPass.php          | 9 +--------
 .../src/RegisterSerializationClassesCompilerPass.php     | 9 +--------
 .../views/src/Plugin/views/field/RenderedEntity.php      | 4 ++--
 core/modules/views/src/Plugin/views/query/Sql.php        | 9 +--------
 core/tests/Drupal/KernelTests/AssertContentTrait.php     | 4 +++-
 .../Core/Authentication/AuthenticationCollectorTest.php  | 5 +----
 21 files changed, 38 insertions(+), 84 deletions(-)

diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationCollector.php b/core/lib/Drupal/Core/Authentication/AuthenticationCollector.php
index de6edae00619..3ac54c0a7e76 100644
--- a/core/lib/Drupal/Core/Authentication/AuthenticationCollector.php
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationCollector.php
@@ -72,10 +72,7 @@ public function getSortedProviders() {
       krsort($this->providerOrders);
 
       // Merge nested providers from $this->providers into $this->sortedProviders.
-      $this->sortedProviders = [];
-      foreach ($this->providerOrders as $providers) {
-        $this->sortedProviders = array_merge($this->sortedProviders, $providers);
-      }
+      $this->sortedProviders = array_merge([], ...$this->providerOrders);
     }
 
     return $this->sortedProviders;
diff --git a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
index f418a5ee2254..c71137b6a34d 100644
--- a/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
+++ b/core/lib/Drupal/Core/Breadcrumb/BreadcrumbManager.php
@@ -107,10 +107,7 @@ protected function getSortedBuilders() {
       // Sort the builders according to priority.
       krsort($this->builders);
       // Merge nested builders from $this->builders into $this->sortedBuilders.
-      $this->sortedBuilders = [];
-      foreach ($this->builders as $builders) {
-        $this->sortedBuilders = array_merge($this->sortedBuilders, $builders);
-      }
+      $this->sortedBuilders = array_merge([], ...$this->builders);
     }
     return $this->sortedBuilders;
   }
diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php
index 51cbaa505c8f..9790a68c536d 100644
--- a/core/lib/Drupal/Core/Config/ConfigManager.php
+++ b/core/lib/Drupal/Core/Config/ConfigManager.php
@@ -264,9 +264,9 @@ public function findConfigEntityDependencies($type, array $names, ConfigDependen
     }
     $dependencies = [];
     foreach ($names as $name) {
-      $dependencies = array_merge($dependencies, $dependency_manager->getDependentEntities($type, $name));
+      $dependencies[] = $dependency_manager->getDependentEntities($type, $name);
     }
-    return $dependencies;
+    return array_merge([], ...$dependencies);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php
index 4e044f96726f..9b94ae80a388 100644
--- a/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php
+++ b/core/lib/Drupal/Core/Config/Schema/SchemaCheckTrait.php
@@ -58,8 +58,9 @@ public function checkConfigSchema(TypedConfigManagerInterface $typed_config, $co
     $this->schema = $typed_config->createFromNameAndData($config_name, $config_data);
     $errors = [];
     foreach ($config_data as $key => $value) {
-      $errors = array_merge($errors, $this->checkValue($key, $value));
+      $errors[] = $this->checkValue($key, $value);
     }
+    $errors = array_merge([], ...$errors);
     if (empty($errors)) {
       return TRUE;
     }
@@ -130,11 +131,12 @@ protected function checkValue($key, $value) {
       if (!is_array($value)) {
         $value = (array) $value;
       }
+      $nested_errors = [];
       // Recurse into any nested keys.
       foreach ($value as $nested_value_key => $nested_value) {
-        $errors = array_merge($errors, $this->checkValue($key . '.' . $nested_value_key, $nested_value));
+        $nested_errors[] = $this->checkValue($key . '.' . $nested_value_key, $nested_value);
       }
-      return $errors;
+      return array_merge($errors, ...$nested_errors);
     }
     // No errors found.
     return [];
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
index 0e02f9536ab3..b6b39c382267 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php
@@ -340,12 +340,14 @@ public function fieldAccess($operation, FieldDefinitionInterface $field_definiti
     $default = $default->andIf($entity_default);
 
     // Invoke hook and collect grants/denies for field access from other
-    // modules. Our default access flag is masked under the ':default' key.
-    $grants = [':default' => $default];
+    // modules.
+    $grants = [];
     $hook_implementations = $this->moduleHandler()->getImplementations('entity_field_access');
     foreach ($hook_implementations as $module) {
-      $grants = array_merge($grants, [$module => $this->moduleHandler()->invoke($module, 'entity_field_access', [$operation, $field_definition, $account, $items])]);
+      $grants[] = [$module => $this->moduleHandler()->invoke($module, 'entity_field_access', [$operation, $field_definition, $account, $items])];
     }
+    // Our default access flag is masked under the ':default' key.
+    $grants = array_merge([':default' => $default], ...$grants);
 
     // Also allow modules to alter the returned grants/denies.
     $context = [
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index 1b22117ae227..6a84fa576be1 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -492,8 +492,9 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
         // implements at least one of them.
         $extra_modules = [];
         foreach ($extra_types as $extra_type) {
-          $extra_modules = array_merge($extra_modules, $this->getImplementations($extra_type . '_alter'));
+          $extra_modules[] = $this->getImplementations($extra_type . '_alter');
         }
+        $extra_modules = array_merge([], ...$extra_modules);
         // If any modules implement one of the extra hooks that do not implement
         // the primary hook, we need to add them to the $modules array in their
         // appropriate order. $this->getImplementations() can only return
diff --git a/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php b/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php
index 07ffec91dd38..172f13ff62c5 100644
--- a/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php
+++ b/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php
@@ -107,13 +107,8 @@ public function isGuesserSupported(): bool {
    *   A sorted array of MIME type guesser objects.
    */
   protected function sortGuessers() {
-    $sorted = [];
     krsort($this->guessers);
-
-    foreach ($this->guessers as $guesser) {
-      $sorted = array_merge($sorted, $guesser);
-    }
-    return $sorted;
+    return array_merge([], ...$this->guessers);
   }
 
 }
diff --git a/core/lib/Drupal/Core/Logger/LoggerChannel.php b/core/lib/Drupal/Core/Logger/LoggerChannel.php
index 13dff9ce38c6..97aae2b858cc 100644
--- a/core/lib/Drupal/Core/Logger/LoggerChannel.php
+++ b/core/lib/Drupal/Core/Logger/LoggerChannel.php
@@ -165,13 +165,8 @@ public function addLogger(LoggerInterface $logger, $priority = 0) {
    *   An array of sorted loggers by priority.
    */
   protected function sortLoggers() {
-    $sorted = [];
     krsort($this->loggers);
-
-    foreach ($this->loggers as $loggers) {
-      $sorted = array_merge($sorted, $loggers);
-    }
-    return $sorted;
+    return array_merge([], ...$this->loggers);
   }
 
 }
diff --git a/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php b/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
index 55a952213adb..b4e8fac7f03e 100644
--- a/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
+++ b/core/lib/Drupal/Core/PathProcessor/PathProcessorManager.php
@@ -131,13 +131,8 @@ protected function getOutbound() {
    *   The processor type to sort, e.g. 'inboundProcessors'.
    */
   protected function sortProcessors($type) {
-    $sorted = [];
     krsort($this->{$type});
-
-    foreach ($this->{$type} as $processors) {
-      $sorted = array_merge($sorted, $processors);
-    }
-    return $sorted;
+    return array_merge([], ...$this->{$type});
   }
 
 }
diff --git a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php
index 74a791dfbdb7..65a358769e04 100644
--- a/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php
+++ b/core/lib/Drupal/Core/RouteProcessor/RouteProcessorManager.php
@@ -71,13 +71,8 @@ protected function getOutbound() {
    * Sorts the processors according to priority.
    */
   protected function sortProcessors() {
-    $sorted = [];
     krsort($this->outboundProcessors);
-
-    foreach ($this->outboundProcessors as $processors) {
-      $sorted = array_merge($sorted, $processors);
-    }
-    return $sorted;
+    return array_merge([], ...$this->outboundProcessors);
   }
 
 }
diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
index 40bf8f4b31db..a9e42778b14c 100644
--- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
+++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php
@@ -77,13 +77,8 @@ public function addTranslator(TranslatorInterface $translator, $priority = 0) {
    *   A sorted array of translator objects.
    */
   protected function sortTranslators() {
-    $sorted = [];
     krsort($this->translators);
-
-    foreach ($this->translators as $translators) {
-      $sorted = array_merge($sorted, $translators);
-    }
-    return $sorted;
+    return array_merge([], ...$this->translators);
   }
 
   /**
diff --git a/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php b/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php
index 0d612a7a356a..cc06c4682eb4 100644
--- a/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php
+++ b/core/modules/config_translation/src/Controller/ConfigTranslationMapperList.php
@@ -71,9 +71,7 @@ public function render() {
       $mappers[$weight] = $mapper;
     }
 
-    foreach ($mappers as $mapper) {
-      $build['#rows'] = array_merge($build['#rows'], $mapper);
-    }
+    $build['#rows'] = array_merge([], ...$mappers);
 
     return $build;
   }
diff --git a/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php b/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php
index f19f4ed37c41..6b057cbc8922 100644
--- a/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php
+++ b/core/modules/field/tests/src/FunctionalJavascript/EntityReference/EntityReferenceAdminTest.php
@@ -359,9 +359,11 @@ protected function assertFieldSelectOptions(string $name, array $expected_option
     $field = $this->assertSession()->selectExists($name);
     $options = $field->findAll('xpath', 'option');
     $optgroups = $field->findAll('xpath', 'optgroup');
+    $nested_options = [];
     foreach ($optgroups as $optgroup) {
-      $options = array_merge($options, $optgroup->findAll('xpath', 'option'));
+      $nested_options[] = $optgroup->findAll('xpath', 'option');
     }
+    $options = array_merge($options, ...$nested_options);
     array_walk($options, function (NodeElement &$option) {
       $option = $option->getAttribute('value');
     });
diff --git a/core/modules/jsonapi/src/Routing/ReadOnlyModeMethodFilter.php b/core/modules/jsonapi/src/Routing/ReadOnlyModeMethodFilter.php
index f8266217a8fd..c4e6c24eb871 100644
--- a/core/modules/jsonapi/src/Routing/ReadOnlyModeMethodFilter.php
+++ b/core/modules/jsonapi/src/Routing/ReadOnlyModeMethodFilter.php
@@ -47,9 +47,10 @@ public function __construct(FilterInterface $inner, ConfigFactoryInterface $conf
   public function filter(RouteCollection $collection, Request $request) {
     $all_supported_methods = [];
     foreach ($collection->all() as $name => $route) {
-      $all_supported_methods = array_merge($all_supported_methods, $route->getMethods());
+      $all_supported_methods[] = $route->getMethods();
     }
 
+    $all_supported_methods = array_merge([], ...$all_supported_methods);
     $collection = $this->inner->filter($collection, $request);
 
     if (!$this->readOnlyModeIsEnabled) {
diff --git a/core/modules/locale/locale.bulk.inc b/core/modules/locale/locale.bulk.inc
index d4a68e0bf00e..611d44b85d66 100644
--- a/core/modules/locale/locale.bulk.inc
+++ b/core/modules/locale/locale.bulk.inc
@@ -305,8 +305,9 @@ function locale_translate_batch_refresh(&$context) {
       // Get list of unique string identifiers and language codes updated.
       $langcodes = array_unique(array_values($context['results']['languages']));
       foreach ($context['results']['stats'] as $report) {
-        $strings = array_merge($strings, $report['strings']);
+        $strings[] = $report['strings'];
       }
+      $strings = array_merge([], ...$strings);
     }
     if ($strings) {
       // Initialize multi-step string refresh.
diff --git a/core/modules/serialization/src/RegisterEntityResolversCompilerPass.php b/core/modules/serialization/src/RegisterEntityResolversCompilerPass.php
index 2e61158dda35..c3bb1d11a9ae 100644
--- a/core/modules/serialization/src/RegisterEntityResolversCompilerPass.php
+++ b/core/modules/serialization/src/RegisterEntityResolversCompilerPass.php
@@ -48,15 +48,8 @@ public function process(ContainerBuilder $container) {
    *   to low priority.
    */
   protected function sort($services) {
-    $sorted = [];
     krsort($services);
-
-    // Flatten the array.
-    foreach ($services as $a) {
-      $sorted = array_merge($sorted, $a);
-    }
-
-    return $sorted;
+    return array_merge([], ...$services);
   }
 
 }
diff --git a/core/modules/serialization/src/RegisterSerializationClassesCompilerPass.php b/core/modules/serialization/src/RegisterSerializationClassesCompilerPass.php
index 3071c59d606f..02c7fa600f6f 100644
--- a/core/modules/serialization/src/RegisterSerializationClassesCompilerPass.php
+++ b/core/modules/serialization/src/RegisterSerializationClassesCompilerPass.php
@@ -74,15 +74,8 @@ public function process(ContainerBuilder $container) {
    *   to low priority.
    */
   protected function sort($services) {
-    $sorted = [];
     krsort($services);
-
-    // Flatten the array.
-    foreach ($services as $a) {
-      $sorted = array_merge($sorted, $a);
-    }
-
-    return $sorted;
+    return array_merge([], ...$services);
   }
 
 }
diff --git a/core/modules/views/src/Plugin/views/field/RenderedEntity.php b/core/modules/views/src/Plugin/views/field/RenderedEntity.php
index 5dd494805378..dce5efcd219d 100644
--- a/core/modules/views/src/Plugin/views/field/RenderedEntity.php
+++ b/core/modules/views/src/Plugin/views/field/RenderedEntity.php
@@ -161,9 +161,9 @@ public function getCacheTags() {
 
     $tags = [];
     foreach ($view_displays as $view_display) {
-      $tags = array_merge($tags, $view_display->getCacheTags());
+      $tags[] = $view_display->getCacheTags();
     }
-    return $tags;
+    return array_merge([], ...$tags);
   }
 
   /**
diff --git a/core/modules/views/src/Plugin/views/query/Sql.php b/core/modules/views/src/Plugin/views/query/Sql.php
index 978d5fe116ca..3c584ba9761d 100644
--- a/core/modules/views/src/Plugin/views/query/Sql.php
+++ b/core/modules/views/src/Plugin/views/query/Sql.php
@@ -1422,14 +1422,7 @@ public function query($get_count = FALSE) {
    * Get the arguments attached to the WHERE and HAVING clauses of this query.
    */
   public function getWhereArgs() {
-    $args = [];
-    foreach ($this->where as $where) {
-      $args = array_merge($args, $where['args']);
-    }
-    foreach ($this->having as $having) {
-      $args = array_merge($args, $having['args']);
-    }
-    return $args;
+    return array_merge([], ...array_column($this->where, 'args'), ...array_column($this->having, 'args'));
   }
 
   /**
diff --git a/core/tests/Drupal/KernelTests/AssertContentTrait.php b/core/tests/Drupal/KernelTests/AssertContentTrait.php
index a76d357ea4a3..f8a99a0ce477 100644
--- a/core/tests/Drupal/KernelTests/AssertContentTrait.php
+++ b/core/tests/Drupal/KernelTests/AssertContentTrait.php
@@ -264,9 +264,11 @@ protected function getAllOptions(\SimpleXMLElement $element) {
 
     // Search option group children.
     if (isset($element->optgroup)) {
+      $nested_options = [];
       foreach ($element->optgroup as $group) {
-        $options = array_merge($options, $this->getAllOptions($group));
+        $nested_options[] = $this->getAllOptions($group);
       }
+      $options = array_merge($options, ...$nested_options);
     }
     return $options;
   }
diff --git a/core/tests/Drupal/Tests/Core/Authentication/AuthenticationCollectorTest.php b/core/tests/Drupal/Tests/Core/Authentication/AuthenticationCollectorTest.php
index 609f4f30f941..6e72d8901dbf 100644
--- a/core/tests/Drupal/Tests/Core/Authentication/AuthenticationCollectorTest.php
+++ b/core/tests/Drupal/Tests/Core/Authentication/AuthenticationCollectorTest.php
@@ -43,10 +43,7 @@ public function testAuthenticationCollector() {
     krsort($providers);
 
     // Merge nested providers from $providers into $sorted_providers.
-    $sorted_providers = [];
-    foreach ($providers as $providers_priority) {
-      $sorted_providers = array_merge($sorted_providers, $providers_priority);
-    }
+    $sorted_providers = array_merge([], ...$providers);
     $this->assertEquals($sorted_providers, $authentication_collector->getSortedProviders());
 
     // Test AuthenticationCollector::getProvider() and
-- 
GitLab