Keywords: PHP 7.2 | each() deprecation | code migration
Abstract: This paper explores the deprecation of the each() function in PHP 7.2 and its impact on existing code, systematically analyzing migration solutions for five typical usage scenarios. By comparing alternative functions like key(), current(), and next() with foreach loops, it provides a complete approach from simple replacements to automated refactoring. The article also discusses the fundamental differences between HTML tags such as <br> and character \n, and introduces the Rector tool for batch migration, helping developers upgrade their code efficiently and safely.
Introduction and Background
With the release of PHP 7.2, the each() function has been officially marked as deprecated. According to the official documentation warning, continued reliance on this function will trigger runtime deprecation notices and may lead to its removal in future PHP versions. This change primarily stems from the inefficiency and usability issues of each() in internal array traversal, with modern PHP favoring foreach loops or other array functions. This paper aims to provide developers with a systematic migration strategy to ensure code compatibility and performance in PHP 7.2 and later versions.
Core Issues and Reasons for Deprecation of each()
The each() function in PHP is used to traverse arrays, returning the key-value pair of the current element and automatically advancing the internal pointer to the next position. A typical usage is list($key, $value) = each($array). However, this function has several notable drawbacks: first, it relies on the array's internal pointer, which can cause state confusion in multi-array operations; second, compared to foreach, each() performs poorly, especially on large arrays; finally, its syntax is obscure, making it less readable than modern loop structures. The PHP community has thus pushed for its deprecation to encourage clearer and more efficient coding practices.
Migration Solutions: Detailed Analysis Based on Scenarios
For common each() usage patterns, we have identified five typical scenarios and provide corresponding migration code. The following analysis primarily references the best answer (Answer 1), supplemented by other answers.
Scenario 1: Retrieving the First Key-Value Pair of an Array
Original code example: $ar = $o->me; reset($ar); list($typ, $val) = each($ar);. Here, each() is used to get the first element of the array. The migration solution is to use the key() and current() functions as replacements: $typ = key($ar); $val = current($ar);. Note that if subsequent code depends on the array pointer position, it may be necessary to call next($ar) to simulate the pointer movement behavior of each(). This approach avoids deprecation warnings while maintaining code clarity.
Scenario 2: Storing a Key-Value Pair as an Array
Original code: $out = array('me' => array(), 'mytype' => 2, '_php_class' => null); $expected = each($out);. Here, each() returns an array containing the key and value. The migration solution is to directly construct the array: $expected = [key($out), current($out)];. This utilizes PHP's array literal syntax, making it concise and efficient. Similarly, pointer management may require adding next($out) depending on the context.
Scenario 3: Looping Through an Array
Original code: for(reset($broken);$kv = each($broken);) {...}. This is a typical array traversal loop. The best migration solution is to use a foreach loop: foreach ($broken as $k => $v) { $kv = [$k, $v]; ... }. foreach automatically handles the pointer, eliminating the need for reset(), and the code is more readable. If the original loop relies on a specific structure of $kv, it can be reassigned within the loop, but typically using $k and $v directly is better.
Scenario 4: Ignoring the Key to Get the Value
Original code: list(, $this->result) = each($this->cache_data);. Here, list() ignores the key and only retrieves the value. The migration solution is to use current(): $this->result = current($this->cache_data);. This directly extracts the value at the current pointer position, avoiding unnecessary array construction. If the code involves pointer movement, consider adding next($this->cache_data).
Scenario 5: Array Traversal with a Limit
Original code: $i = 0; reset($array); while( (list($id, $item) = each($array)) || $i < 30 ) { ... $i++; }. This is a complex scenario combining array traversal with a counter. The migration solution uses a for loop combined with pointer functions: reset($array); for ($i = 0; $i < 30; $i++) { $id = key($array); $item = current($array); ... next($array); }. This explicitly controls the loop count and pointer movement, avoiding the deprecation issue of each(). Note that if the array length is less than 30, this solution may end early, requiring adjustment based on business logic.
Supplementary Migration Strategies and Tool Support
In addition to the manual migration above, other answers provide valuable supplements. For example, Answer 3 summarizes three general patterns: when ignoring the value, use foreach(array_keys($array) as $key); when ignoring the key, use foreach($array as $value); and when both key and value are needed, use foreach($array as $key => $value). These patterns cover most each() usage scenarios, simplifying the migration process.
For large projects, manual migration can be time-consuming and error-prone. Answer 2 recommends the automated tool Rector, which can batch convert each() code to foreach or other alternative structures. Steps include installing Rector, configuring the PHP_72 rule set, and running it on the codebase. For example, the command vendor/bin/rector process src --set php72 can automatically process files in the src directory. This improves migration efficiency, but note that the tool may not cover all edge cases, so manual review is advised.
Answer 4 proposes a custom each() function solution, such as defining a myEach() function to mimic the original behavior. While this provides temporary compatibility, it is not recommended for long-term use as it may mask code modernity issues and increase maintenance burden. A better approach is to migrate directly to standard PHP functions.
Practical Recommendations and Conclusion
During migration, developers should first assess the usage scenarios of each() in their code, prioritizing refactoring with foreach loops for optimal readability and performance. For simple scenarios, combinations of key(), current(), and next() are effective alternatives. It is crucial to test migrated code to ensure correct pointer behavior and logic, especially in cases involving multiple arrays or complex loops.
Additionally, note HTML escaping issues in code: for example, when mentioning HTML tags like <br> in descriptive text, angle brackets should be escaped to avoid parsing errors, as shown in this paper. This ensures proper display of content in web environments.
In summary, migrating from each() is part of PHP modernization. By adopting the strategies outlined in this paper, developers can enhance code quality, ensure compatibility, and prepare for future PHP versions. It is recommended to combine automated tools with manual optimization for efficient and reliable upgrades.