Don't use array_merge() inside a loop body
The title is don’t use array_merge() in the loop body. In fact, this is just one of the conclusions of this article
Let’s study the merging of arrays in the PHP language (recursive merging is not considered here)
Comparison of four ways to merge arrays
Comparison of four common ways to merge arrays
Writing code
We know that both array_merge() and operators can splice arrays
Create a class
ArrayMerge()
● EachOne() loop body uses array_merge() merge
● EachTwo() uses array_merge() to merge after the loop body ends
● eachThree() loop body is nested to implement array merging
● eachFour() loop body uses operators to splice and merge
● getNiceFileSize() Convert the memory usage into a human-readable format
/** * Class ArrayMerge */ class ArrayMerge { /** * @param int $times * @return array */ public static function eachOne(int $times): array { $a = []; $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for ($i = 0; $i < $times; $i++) { $a = array_merge($a, $b); } return $a; } /** * @param int $times * @return array */ public static function eachTwo(int $times): array { $a = [[]]; $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for ($i = 0; $i < $times; $i++) { $a[] = $b; } return array_merge(...$a); } /** * @param int $times * @return array */ public static function eachThree(int $times): array { $a = []; $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for ($i = 0; $i < $times; $i++) { foreach ($b as $item) { $a[] = $item; } } return $a; } /** * @param int $times * @return array */ public static function eachFour(int $times): array { $a = []; $b = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; for ($i = 0; $i < $times; $i++) { $a = $b + $a; } return $a; } /** * 转化内存信息 * @param $bytes * @param bool $binaryPrefix * @return string */ public static function getNiceFileSize(int $bytes, $binaryPrefix = true): ?string { if ($binaryPrefix) { $unit = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'); if ($bytes === 0) { return '0 ' . $unit[0]; } return @round($bytes / (1024 ** ($i = floor(log($bytes, 1024)))), 2) . ' ' . ($unit[(int)$i] ?? 'B'); } $unit = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); if ($bytes === 0) { return '0 ' . $unit[0]; } return @round($bytes / (1000 ** ($i = floor(log($bytes, 1000)))), 2) . ' ' . ($unit[(int)$i] ?? 'B'); } }
Use
First allocate more memory
Output the memory usage, The length of the merged array, and record the time of each step
ini_set('memory_limit', '4000M'); $timeOne = microtime(true); $a = ArrayMerge::eachOne(10000); echo 'count eachOne Result | ' . count($a) . PHP_EOL; echo 'memory eachOne Result | ' . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL; $timeTwo = microtime(true); $b = ArrayMerge::eachTwo(10000); echo 'count eachTwo Result | ' . count($b) . PHP_EOL; echo 'memory eachTwo Result | ' . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL; $timeThree = microtime(true); $c = ArrayMerge::eachThree(10000); echo 'count eachThree Result | ' . count($c) . PHP_EOL; echo 'memory eachThree Result | ' . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL; $timeFour = microtime(true); $d = ArrayMerge::eachFour(10000); echo 'count eachFour Result | ' . count($d) . PHP_EOL; echo 'memory eachFour Result | ' . ArrayMerge::getNiceFileSize(memory_get_usage(true)) . PHP_EOL; $timeFive = microtime(true); echo PHP_EOL; echo 'eachOne | ' . ($timeTwo - $timeOne) . PHP_EOL; echo 'eachTwo | ' . ($timeThree - $timeTwo) . PHP_EOL; echo 'eachThree | ' . ($timeFour - $timeThree) . PHP_EOL; echo 'eachFour | ' . ($timeFive - $timeFour) . PHP_EOL; echo PHP_EOL;
Result
count eachOne Result | 100000 memory eachOne Result | 9 MiB count eachTwo Result | 100000 memory eachTwo Result | 14 MiB count eachThree Result | 100000 memory eachThree Result | 18 MiB count eachFour Result | 10 #注意这里 memory eachFour Result | 18 MiB eachOne | 5.21253490448 # 循环体中使用array_merge()最慢,而且耗费内存 eachTwo | 0.0071840286254883 # 循环体结束后使用array_merge()最快 eachThree | 0.037622928619385 # 循环体嵌套比循环体结束后使用array_merge()慢三倍 eachFour | 0.0072360038757324 # 看似也很快,但是合并的结果有问题
● Using array_merge () in the loop body is the slowest and consumes memory
● Using array_merge () after the loop body ends is the fastest
● Loop body nesting is three times slower than using array_merge () after the loop body ends.
● It seems to be very fast, But there is a problem with the merged result
The pitfalls of merging arrays
We noticed that the result length of eachFour just now is only 10
Let’s explore why this happens Such a result
Here are the recursive merges for comparison
Code
public static function test(): void { $testA = [ '111' => 'testA1', 'abc' => 'testA1', '222' => 'testA2', ]; $testB = [ '111' => 'testB1', 'abc' => 'testB1', '222' => 'testB2', 'www' => 'testB1', ]; echo 'array_merge($testA, $testB) | ' . PHP_EOL; print_r(array_merge($testA, $testB)); echo '$testA + $testB | ' . PHP_EOL; print_r($testA + $testB); echo '$testB + $testA | ' . PHP_EOL; print_r($testB + $testA); echo 'array_merge_recursive($testA, $testB) | ' . PHP_EOL; print_r(array_merge_recursive($testA, $testB)); }
Result
number to splice two arrays, the latter will only supplement the keys that the former does not have, but will retain the numeric index
array_merge() and array_merge_recursive() will erase the numeric index, and all numeric indexes will start from 0 in order
array_merge($testA, $testB) | #数字索引强制从0开始了 字符key相同的以后者为准 Array ( [0] => testA1 [abc] => testB1 [1] => testA2 [2] => testB1 [3] => testB2 [www] => testB1 ) $testA + $testB | #testA得到保留,testB补充了testA中没有的key,数字索引得到保留 Array ( [111] => testA1 [abc] => testA1 [222] => testA2 [www] => testB1 ) $testB + $testA | #testB得到保留,testA补充了testB中没有的key,数字索引得到保留 Array ( [111] => testB1 [abc] => testB1 [222] => testB2 [www] => testB1 )
array_merge_recursive($testA, $testB) | #The numerical indexes start from 0, but the order of the array is not destroyed. The same string `key` is merged into an array
Array ( [0] => testA1 [abc] => Array ( [0] => testA1 [1] => testB1 ) [1] => testA2 [2] => testB1 [3] => testB2 [www] => testB1 )
Analysis
You must be very confused after seeing this. I didn’t expect array_merge() to have such pitfalls
Let’s take a look at the official manual first
array_merge ( array $array1 [, array $... ] ) : array
array_merge () Merges the cells of one or more arrays, with the values in one array appended to the previous array. Returns the resulting array.
If the input array has the same string key name, the value after the key name will overwrite the previous value. However, if the array contains numeric keys, the subsequent values will not overwrite the original values but will be appended to them.
If only an array is given and the array is numerically indexed, the key names are re-indexed in a consecutive manner.
Only if the string key name is the same, the subsequent value will overwrite the previous value. (But the manual does not explain why the index of the numeric key name was reset)
Then let’s take a look at the source code
PHPAPI int php_array_merge(HashTable *dest, HashTable *src) { zval *src_entry; zend_string *string_key; if ((dest->u.flags & HASH_FLAG_PACKED) && (src->u.flags & HASH_FLAG_PACKED)) { // 自然数组的合并,HASH_FLAG_PACKED表示数组是自然数组([0,1,2]) 参考http://ju.outofmemory.cn/entry/197064 zend_hash_extend(dest, zend_hash_num_elements(dest) + zend_hash_num_elements(src), 1); ZEND_HASH_FILL_PACKED(dest) { ZEND_HASH_FOREACH_VAL(src, src_entry) { if (UNEXPECTED(Z_ISREF_P(src_entry)) && UNEXPECTED(Z_REFCOUNT_P(src_entry) == 1)) { ZVAL_UNREF(src_entry); } Z_TRY_ADDREF_P(src_entry); ZEND_HASH_FILL_ADD(src_entry); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FILL_END(); } else { //遍历获取key和vaule ZEND_HASH_FOREACH_STR_KEY_VAL(src, string_key, src_entry) { if (UNEXPECTED(Z_ISREF_P(src_entry) && Z_REFCOUNT_P(src_entry) == 1)) { ZVAL_UNREF(src_entry); } Z_TRY_ADDREF_P(src_entry); // 参考https://github.com/pangudashu/php7-internal/blob/master/7/var.md if (string_key) { // 字符串key(zend_string) 插入或者更新元素,会增加key的计数 zend_hash_update(dest, string_key, src_entry); } else { //插入新元素,使用自动的索引值(破案了,索引被重置的原因在此) zend_hash_next_index_insert_new(dest, src_entry); } } ZEND_HASH_FOREACH_END(); } return 1; }
Summary
Summary As mentioned above, different methods of merging arrays have certain flaws, but through our above exploration, we learned that
● It is not advisable to use array_merge() in the loop body to merge arrays, and the speed difference is up to a hundred times
● Array_merge() should be used with caution when merging arrays. If the key is important and the key may be a number, array_merge() cannot be used to merge. We can use nested loop bodies (note that the inner loop uses key for assignment) Operation)
● If you pay attention to the key, and the key may be a number, you can use operators to simply merge arrays, but be sure not to use them in the loop body, because the result of each operation is to generate a new Array
The above is the detailed content of Don't use array_merge() inside a loop body. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



Alipay PHP...

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Article discusses late static binding (LSB) in PHP, introduced in PHP 5.3, allowing runtime resolution of static method calls for more flexible inheritance.Main issue: LSB vs. traditional polymorphism; LSB's practical applications and potential perfo

Article discusses essential security features in frameworks to protect against vulnerabilities, including input validation, authentication, and regular updates.

The article discusses adding custom functionality to frameworks, focusing on understanding architecture, identifying extension points, and best practices for integration and debugging.

Sending JSON data using PHP's cURL library In PHP development, it is often necessary to interact with external APIs. One of the common ways is to use cURL library to send POST�...

The application of SOLID principle in PHP development includes: 1. Single responsibility principle (SRP): Each class is responsible for only one function. 2. Open and close principle (OCP): Changes are achieved through extension rather than modification. 3. Lisch's Substitution Principle (LSP): Subclasses can replace base classes without affecting program accuracy. 4. Interface isolation principle (ISP): Use fine-grained interfaces to avoid dependencies and unused methods. 5. Dependency inversion principle (DIP): High and low-level modules rely on abstraction and are implemented through dependency injection.

An official introduction to the non-blocking feature of ReactPHP in-depth interpretation of ReactPHP's non-blocking feature has aroused many developers' questions: "ReactPHPisnon-blockingbydefault...
