Issue #3266568 by mxr576, sourabhjain, quietone: Refactor array_merge() usage in loops as possible for performance

merge-requests/3490/head
catch 2023-02-17 12:16:21 +00:00
parent 74f7e5acc8
commit 8df6544ec1
26 changed files with 68 additions and 57 deletions

View File

@ -72,7 +72,7 @@ class AuthenticationCollector implements AuthenticationCollectorInterface {
krsort($this->providerOrders);
// Merge nested providers from $this->providers into $this->sortedProviders.
$this->sortedProviders = array_merge([], ...$this->providerOrders);
$this->sortedProviders = array_merge(...$this->providerOrders);
}
return $this->sortedProviders;

View File

@ -107,7 +107,7 @@ class BreadcrumbManager implements ChainBreadcrumbBuilderInterface {
// Sort the builders according to priority.
krsort($this->builders);
// Merge nested builders from $this->builders into $this->sortedBuilders.
$this->sortedBuilders = array_merge([], ...$this->builders);
$this->sortedBuilders = array_merge(...$this->builders);
}
return $this->sortedBuilders;
}

View File

@ -264,7 +264,7 @@ class ConfigManager implements ConfigManagerInterface {
foreach ($names as $name) {
$dependencies[] = $dependency_manager->getDependentEntities($type, $name);
}
return array_merge([], ...$dependencies);
return array_merge(...$dependencies);
}
/**
@ -292,9 +292,9 @@ class ConfigManager implements ConfigManagerInterface {
$storage = $this->entityTypeManager->getStorage($entity_type_id);
// Remove the keys since there are potential ID clashes from different
// configuration entity types.
$entities_to_return = array_merge($entities_to_return, array_values($storage->loadMultiple($entities_to_load)));
$entities_to_return[] = array_values($storage->loadMultiple($entities_to_load));
}
return $entities_to_return;
return array_merge(...$entities_to_return);
}
/**
@ -487,13 +487,14 @@ class ConfigManager implements ConfigManagerInterface {
$missing_dependencies = [];
foreach ($this->activeStorage->readMultiple($this->activeStorage->listAll()) as $config_data) {
if (isset($config_data['dependencies']['content'])) {
$content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['content']);
$content_dependencies[] = $config_data['dependencies']['content'];
}
if (isset($config_data['dependencies']['enforced']['content'])) {
$content_dependencies = array_merge($content_dependencies, $config_data['dependencies']['enforced']['content']);
$content_dependencies[] = $config_data['dependencies']['enforced']['content'];
}
}
foreach (array_unique($content_dependencies) as $content_dependency) {
$unique_content_dependencies = array_unique(array_merge(...$content_dependencies));
foreach ($unique_content_dependencies as $content_dependency) {
// Format of the dependency is entity_type:bundle:uuid.
[$entity_type, $bundle, $uuid] = explode(':', $content_dependency, 3);
if (!$this->entityRepository->loadEntityByUuid($entity_type, $uuid)) {

View File

@ -129,7 +129,8 @@ class Query extends QueryBase implements QueryInterface {
$prefix_length = strlen($prefix);
// Search the conditions for restrictions on configuration object names.
$names = FALSE;
$filter_by_names = [];
$has_added_restrictions = FALSE;
$id_condition = NULL;
$id_key = $this->entityType->getKey('id');
if ($this->condition->getConjunction() == 'AND') {
@ -140,21 +141,22 @@ class Query extends QueryBase implements QueryInterface {
if (is_string($condition['field']) && ($operator == 'IN' || $operator == '=')) {
// Special case ID lookups.
if ($condition['field'] == $id_key) {
$has_added_restrictions = TRUE;
$ids = (array) $condition['value'];
$names = array_map(function ($id) use ($prefix) {
$filter_by_names[] = array_map(static function ($id) use ($prefix) {
return $prefix . $id;
}, $ids);
}
elseif (in_array($condition['field'], $lookup_keys)) {
$has_added_restrictions = TRUE;
// If we don't find anything then there are no matches. No point in
// listing anything.
$names = [];
$keys = (array) $condition['value'];
$keys = array_map(function ($value) use ($condition) {
$keys = array_map(static function ($value) use ($condition) {
return $condition['field'] . ':' . $value;
}, $keys);
foreach ($this->getConfigKeyStore()->getMultiple($keys) as $list) {
$names = array_merge($names, $list);
$filter_by_names[] = $list;
}
}
}
@ -166,7 +168,7 @@ class Query extends QueryBase implements QueryInterface {
// We stop at the first restricting condition on name. In the case where
// there are additional restricting conditions, results will be
// eliminated when the conditions are checked on the loaded records.
if ($names !== FALSE) {
if ($has_added_restrictions !== FALSE) {
// If the condition has been responsible for narrowing the list of
// configuration to check there is no point in checking it further.
unset($conditions[$condition_key]);
@ -174,52 +176,56 @@ class Query extends QueryBase implements QueryInterface {
}
}
}
// If no restrictions on IDs were found, we need to parse all records.
if ($names === FALSE) {
$names = $this->configFactory->listAll($prefix);
if ($has_added_restrictions === FALSE) {
$filter_by_names = $this->configFactory->listAll($prefix);
}
else {
$filter_by_names = array_merge(...$filter_by_names);
}
// In case we have an ID condition, try to narrow down the list of config
// objects to load.
if ($id_condition && !empty($names)) {
if ($id_condition && !empty($filter_by_names)) {
$value = $id_condition['value'];
$filter = NULL;
switch ($id_condition['operator']) {
case '<>':
$filter = function ($name) use ($value, $prefix_length) {
$filter = static function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return $id !== $value;
};
break;
case 'STARTS_WITH':
$filter = function ($name) use ($value, $prefix_length) {
$filter = static function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return strpos($id, $value) === 0;
};
break;
case 'CONTAINS':
$filter = function ($name) use ($value, $prefix_length) {
$filter = static function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return strpos($id, $value) !== FALSE;
};
break;
case 'ENDS_WITH':
$filter = function ($name) use ($value, $prefix_length) {
$filter = static function ($name) use ($value, $prefix_length) {
$id = substr($name, $prefix_length);
return strrpos($id, $value) === strlen($id) - strlen($value);
};
break;
}
if ($filter) {
$names = array_filter($names, $filter);
$filter_by_names = array_filter($filter_by_names, $filter);
}
}
// Load the corresponding records.
$records = [];
foreach ($this->configFactory->loadMultiple($names) as $config) {
foreach ($this->configFactory->loadMultiple($filter_by_names) as $config) {
$records[substr($config->getName(), $prefix_length)] = $config->get();
}
return $records;

View File

@ -88,9 +88,9 @@ class PreExistingConfigException extends ConfigException {
}
return $config_name;
}, $config_names);
$flat_config_objects = array_merge($flat_config_objects, $config_names);
$flat_config_objects[] = $config_names;
}
return $flat_config_objects;
return array_merge(...$flat_config_objects);
}
}

View File

@ -56,7 +56,7 @@ trait SchemaCheckTrait {
foreach ($config_data as $key => $value) {
$errors[] = $this->checkValue($key, $value);
}
$errors = array_merge([], ...$errors);
$errors = array_merge(...$errors);
if (empty($errors)) {
return TRUE;
}

View File

@ -560,8 +560,9 @@ class SqlContentEntityStorage extends ContentEntityStorageBase implements SqlEnt
// returns an array keyed by property names so remove the keys
// before array_merge() to avoid losing data with fields having the
// same columns i.e. value.
$column_names = array_merge($column_names, array_values($table_mapping->getColumnNames($data_field)));
$column_names[] = array_values($table_mapping->getColumnNames($data_field));
}
$column_names = array_merge(...$column_names);
$query->fields('data', $column_names);
}

View File

@ -499,7 +499,7 @@ class ModuleHandler implements ModuleHandlerInterface {
foreach ($extra_types as $extra_type) {
$extra_modules[] = array_keys($this->getImplementationInfo($extra_type . '_alter'));
}
$extra_modules = array_merge([], ...$extra_modules);
$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->getImplementationInfo() can only return

View File

@ -700,7 +700,8 @@ class FileSystem implements FileSystemInterface {
* @see \Drupal\Core\File\FileSystemInterface::scanDirectory()
*/
protected function doScanDirectory($dir, $mask, array $options = [], $depth = 0) {
$files = [];
$files_in_sub_dirs = [];
$files_in_this_directory = [];
// Avoid warnings when opendir does not have the permissions to open a
// directory.
if ($handle = @opendir($dir)) {
@ -714,19 +715,17 @@ class FileSystem implements FileSystemInterface {
$uri = "$dir/$filename";
}
if ($options['recurse'] && is_dir($uri)) {
// Give priority to files in this folder by merging them in after
// any subdirectory files.
$files = array_merge($this->doScanDirectory($uri, $mask, $options, $depth + 1), $files);
$files_in_sub_dirs[] = $this->doScanDirectory($uri, $mask, $options, $depth + 1);
}
elseif ($depth >= $options['min_depth'] && preg_match($mask, $filename)) {
// Always use this match over anything already set in $files with
// the same $options['key'].
// Always use this match over anything already set with the same
// $options['key'].
$file = new \stdClass();
$file->uri = $uri;
$file->filename = $filename;
$file->name = pathinfo($filename, PATHINFO_FILENAME);
$key = $options['key'];
$files[$file->$key] = $file;
$files_in_this_directory[$file->$key] = $file;
if ($options['callback']) {
$options['callback']($uri);
}
@ -739,7 +738,9 @@ class FileSystem implements FileSystemInterface {
$this->logger->error('@dir can not be opened', ['@dir' => $dir]);
}
return $files;
// Give priority to files in this folder by merging them after
// any subdirectory files.
return array_merge(array_merge(...$files_in_sub_dirs), $files_in_this_directory);
}
}

View File

@ -108,7 +108,7 @@ class MimeTypeGuesser implements MimeTypeGuesserInterface {
*/
protected function sortGuessers() {
krsort($this->guessers);
return array_merge([], ...$this->guessers);
return array_merge(...$this->guessers);
}
}

View File

@ -166,7 +166,7 @@ class LoggerChannel implements LoggerChannelInterface {
*/
protected function sortLoggers() {
krsort($this->loggers);
return array_merge([], ...$this->loggers);
return array_merge(...$this->loggers);
}
}

View File

@ -132,7 +132,7 @@ class PathProcessorManager implements InboundPathProcessorInterface, OutboundPat
*/
protected function sortProcessors($type) {
krsort($this->{$type});
return array_merge([], ...$this->{$type});
return array_merge(...$this->{$type});
}
}

View File

@ -72,7 +72,7 @@ class RouteProcessorManager implements OutboundRouteProcessorInterface {
*/
protected function sortProcessors() {
krsort($this->outboundProcessors);
return array_merge([], ...$this->outboundProcessors);
return array_merge(...$this->outboundProcessors);
}
}

View File

@ -36,14 +36,14 @@ class MethodFilter implements FilterInterface {
}
if (!in_array($method, $supported_methods, TRUE)) {
$all_supported_methods = array_merge($supported_methods, $all_supported_methods);
$all_supported_methods[] = $supported_methods;
$collection->remove($name);
}
}
if (count($collection)) {
return $collection;
}
throw new MethodNotAllowedException(array_unique($all_supported_methods));
throw new MethodNotAllowedException(array_unique(array_merge(...$all_supported_methods)));
}
}

View File

@ -78,7 +78,7 @@ class TranslationManager implements TranslationInterface, TranslatorInterface {
*/
protected function sortTranslators() {
krsort($this->translators);
return array_merge([], ...$this->translators);
return array_merge(...$this->translators);
}
/**

View File

@ -183,8 +183,9 @@ class Attribute implements \ArrayAccess, \IteratorAggregate, MarkupInterface {
// Merge the values passed in from the classes array.
// The argument is cast to an array to support comma separated single
// values or one or more array arguments.
$classes = array_merge($classes, (array) $arg);
$classes[] = (array) $arg;
}
$classes = array_merge(...$classes);
// Merge if there are values, just add them otherwise.
if (isset($this->storage['class']) && $this->storage['class'] instanceof AttributeArray) {
@ -271,8 +272,9 @@ class Attribute implements \ArrayAccess, \IteratorAggregate, MarkupInterface {
// Merge the values passed in from the classes array.
// The argument is cast to an array to support comma separated single
// values or one or more array arguments.
$classes = array_merge($classes, (array) $arg);
$classes[] = (array) $arg;
}
$classes = array_merge(...$classes);
// Remove the values passed in from the value array. Use array_values() to
// ensure that the array index remains sequential.

View File

@ -90,9 +90,9 @@ class JUnitConverter {
if ($file && !$child->attributes()->file) {
$child->addAttribute('file', $file);
}
$test_cases = array_merge($test_cases, static::findTestCases($child, $element));
$test_cases[] = static::findTestCases($child, $element);
}
return $test_cases;
return array_merge(...$test_cases);
}
/**

View File

@ -195,12 +195,12 @@ trait TestSetupTrait {
$exceptions = [];
while ($class) {
if (property_exists($class, 'configSchemaCheckerExclusions')) {
$exceptions = array_merge($exceptions, $class::$configSchemaCheckerExclusions);
$exceptions[] = $class::$configSchemaCheckerExclusions;
}
$class = get_parent_class($class);
}
// Filter out any duplicates.
return array_unique($exceptions);
return array_unique(array_merge(...$exceptions));
}
}

View File

@ -71,7 +71,7 @@ class ConfigTranslationMapperList extends ControllerBase {
$mappers[$weight] = $mapper;
}
$build['#rows'] = array_merge([], ...$mappers);
$build['#rows'] = array_merge(...$mappers);
return $build;
}

View File

@ -50,7 +50,7 @@ class ReadOnlyModeMethodFilter implements FilterInterface {
$all_supported_methods[] = $route->getMethods();
}
$all_supported_methods = array_merge([], ...$all_supported_methods);
$all_supported_methods = array_merge(...$all_supported_methods);
$collection = $this->inner->filter($collection, $request);
if (!$this->readOnlyModeIsEnabled) {

View File

@ -308,7 +308,7 @@ function locale_translate_batch_refresh(&$context) {
foreach ($context['results']['stats'] as $report) {
$strings[] = $report['strings'];
}
$strings = array_merge([], ...$strings);
$strings = array_merge(...$strings);
}
if ($strings) {
// Initialize multi-step string refresh.

View File

@ -49,7 +49,7 @@ class RegisterEntityResolversCompilerPass implements CompilerPassInterface {
*/
protected function sort($services) {
krsort($services);
return array_merge([], ...$services);
return array_merge(...$services);
}
}

View File

@ -75,7 +75,7 @@ class RegisterSerializationClassesCompilerPass implements CompilerPassInterface
*/
protected function sort($services) {
krsort($services);
return array_merge([], ...$services);
return array_merge(...$services);
}
}

View File

@ -163,7 +163,7 @@ class RenderedEntity extends FieldPluginBase implements CacheableDependencyInter
foreach ($view_displays as $view_display) {
$tags[] = $view_display->getCacheTags();
}
return array_merge([], ...$tags);
return array_merge(...$tags);
}
/**

View File

@ -1429,7 +1429,7 @@ class Sql extends QueryPluginBase {
* Get the arguments attached to the WHERE and HAVING clauses of this query.
*/
public function getWhereArgs() {
return array_merge([], ...array_column($this->where, 'args'), ...array_column($this->having, 'args'));
return array_merge(...array_column($this->where, 'args'), ...array_column($this->having, 'args'));
}
/**

View File

@ -43,7 +43,7 @@ class AuthenticationCollectorTest extends UnitTestCase {
krsort($providers);
// Merge nested providers from $providers into $sorted_providers.
$sorted_providers = array_merge([], ...$providers);
$sorted_providers = array_merge(...$providers);
$this->assertEquals($sorted_providers, $authentication_collector->getSortedProviders());
// Test AuthenticationCollector::getProvider() and