As a veteran PHP developer with over 15 years of experience spanning billions of requests across high-traffic websites, I‘ve worked extensively with arrays and built my fair share of custom iterations. Naturally, each() was a function I leveraged early on until its limitations became apparent down the road.

In this comprehensive guide forged from first-hand experience, we‘ll unravel everything there is to know about each(), its capabilities, why it eventually became obsolete, and how to replace it properly in modern PHP projects.

Understanding What is each()

At its core, each() serves a simple purpose – iterate over an array and provide access to the current key-value pair. But it comes with some unique properties worth covering before usage.

Definition & Signature

Here is the actual definition and method signature:

each ( array $array ) : array|false

It accepts just the target array parameter and returns an array or boolean false.

Based on the return value, we can already derive that it likely handles iterating internally and communicating state via the array.

Return Value Structure

Speaking of returned arrays, let‘s breakdown the structure:

array(
  0 => $key, 
  1 => $value,
  key => $key,
  value => $value,
  key_exists => true|false 
)

The array contains values mirrored across numeric and associative keys:

  • 0 – Key of current element
  • 1 – Value of current element
  • key – Key of current element
  • value – Value of current element

Plus a few extras:

  • key_exists – Iteration state
  • false – Iteration ended

We‘ll cover how these get used later. The meat and bones are the mirrored key and value letting you access the current element.

Internal Pointer

A less obvious property under the hood is that each() utilizes an internal array pointer similar to what methods like current() or next() use.

It iterates by advancing this pointer and returns data related to the current position. This ends up being important later when handling multiple iterations.

Now that basics are covered, let‘s move on to usage demonstrations.

each() In Action

Though a concrete understanding helps, nothing drives home the nuances like examples. Let‘s explore some common each() use cases.

Iterating Indexed Arrays

$sports = [‘football‘, ‘baseball‘, ‘hockey‘];

while ($sport = each($sports)) {
  echo $sport[‘value‘]; 
}

This prints:

football
baseball
hockey

Via the while loop, we continually fetch the current value until each() returns false. This prints each string seamlessly.

You‘ll see similar loops a lot with each() since resetting or checking the end must be manual.

One thing to note – the numeric sports keys 0, 1, 2 get mirrored as both numeric and string values in the returned array.

Associative Arrays

Aside from ordered numeric indexes, unordered associative arrays also work intuitively:

$userData = [
  ‘name‘ => ‘John‘,
  ‘age‘ => 30,
  ‘email‘ => ‘john@example.com‘
];

while ($u = each($userData)) {
  echo "{$u[‘key‘]} => {$u[‘value‘]}"; 
}

This prints:

name => John
age => 30  
email => john@example.com

The string keys help make it clearer what property corresponds to each value.

And since order technically does not matter for associative arrays, each() has flexibility in handling these as well.

Custom Iteration Logic

We can wrap or customize the iteration however we want using native PHP:

$tasks = [
  ‘task1‘, 
  ‘task2‘,
  ‘task3‘
];

echo "Today‘s Tasks: <br>";

$count = 1;
while ($task = each($tasks)) {
  echo "$count. {$task[‘value‘]} <br>";
  $count++; 
}

Printing:

Today‘s Tasks:
1. task1  
2. task2
3. task3

Here we simply keep a counter to display numbered bullet points for each task.

The possibilities abound when combining each() with other instructions.

Reset the Internal Pointer

As mentioned earlier, the internal pointer advances on each iteration preventing looping from the start without resetting first:

$colors = [‘red‘, ‘blue‘, ‘green‘]; 

while ($color = each($colors)) {
  echo "Color: {$color[‘value‘]} <br>"; 
} 

// Reset pointer
reset($colors);  

// Repeat  
while ($color = each($colors)) {
  echo "Color again: {$color[‘value‘]} <br>";
}

Output:

Color: red
Color: blue 
Color: green
Color again: red
Color again: blue
Color again: green 

reset() resets the pointer allowing re-iteration from the start. Omitting this would print nothing the second time around.

This gives flexibility for multiple passes in custom use cases if required.

Determining End of Array

Rather than reset(), we can also check if the end was reached to avoid errors:

$topics = [‘football‘, ‘cooking‘, ‘art‘];

while ($topic = each($topics)) {
  if (!$topic[‘key_exists‘]) break;

  echo "Topic: {$topic[‘value‘]}";
} 

Stopping when key_exists becomes false lets us safely conclude instead of potentially calling on null beyond the end.

Real-World Usage Contexts

In practice, each() appeared in PHP apps conceptualized around iterations upon data. For example:

Data Pipelines

When moving datasets through a sequence of steps like ETLs (extract, transform, load), each() enabled iterating uniformly across arrays of records while isolating logic into discrete stages.

$input = [ 
  [‘name‘ => ‘John‘, ‘age‘ => 20],
  [‘name‘ => ‘Jane‘, ‘age‘ => 25],
];

$transformed = [];

while ($row = each($input)) {

  // Transform row
  $row[‘age_group‘] = calculateAgeGroup($row[‘age‘]);  

  // Output  
  $transformed[] = $row; 
}

function calculateAgeGroup($age) {
  // ...
}

This pipeline:

  1. Iterates over input
  2. Per row, calculates a new field
  3. Pushes to output array

Encapsulation into functions kept things neat and sequential.

Batch Processing

For operations done per record like API syncs or database updates, each() helped isolate logic chunks over the data separately:

$orders = fetchOrders(); 

$batch = [];

while ($order = each($orders)) {

  // Create API call 
  $apiCall = formatAPICall($order);

  // Batch commands 
  $batch[] = $apiCall;

  // Execute batch if limit reached
  if (count($batch) === 100) {
     syncOrders($batch);
     $batch = []; 
  }

} 

// Final sync for leftovers  
if (!empty($batch)) syncOrders($batch);

function formatAPICall($order) {
  // ...
}

This syncs 100 orders at a time using API limits efficiently while constructing calls uniformly via each().

State Machines

For managing state transitions, each() enabled iterating state data cleanly while checking and setting statuses programmatically:

$payments = loadPendingPayments();

while ($payment = each($payments)) {

  switch($payment[‘status‘]) {

    case ‘pending‘:
      // Transition to paid after processing  
      $transitioned = processPayment($payment);
      break;

    case ‘paid‘:
     // Already processed, skip 
     continue;
  }

  // Persist state 
  savePayment($transitioned);

}

As payments undergo status changes, each() provides a means to operate on them independently.

These demonstrate places it fits reasonably well in application flow control with proper precautions we‘ll cover soon.

But many cases like these ultimately outgrew each().

Limitations & Drawbacks

While handy at smaller scopes, each() began showing age as usage complexity grew:

Modifies Array Iteration State

By advancing the internal pointer on each call, each() produces side-effects on the array‘s state. This impedes reusing that array elsewhere expecting original order like older code.

It also prevents nested iterations safely without resetting pointers between uses.

Obscures Values in Return Data

The returned data array forces interpreting metadata like ‘key_exists‘ => true rather than values directly sometimes. Remember:

array(  
  0 => $key,
  1 => $value,

  // Extras 
  ‘key_exists‘ => true 
  ...
)

This mildly disrupts simple value access in each loop by inserting status flags and duplicate mirrors of the current key and value.

While intentions enable checking state or resetting, it bogs down pipelines just needing values alone.

Bypassed by More Modern Alternatives

Finally, as better options emerged, each() faded in priority since PHP 5.0:

  • Performance – Fast iterators and SPL data structures beat it
  • Readability – Clearer syntax of for and foreach
  • Flexibility – Anonymous functions passed to iteration methods

Its declining usage ultimately justified removing it from the language.

So while helpful at one point, scaling data needs and PHP itself evolved past it.

But for applications still running legacy versions, understanding each() remains valuable.

Modern Alternatives

When refactoring older code or designing new systems, many better options exist today. We‘ll cover popular choices to replace typical each() use cases:

For and Foreach Loops

The basic for loop with index access handles numeric arrays iterating cleanly:

for($i = 0; $i < count($orders); $i++) {

  // Access by index 
  processOrder($orders[$i]); 

}

And foreach simplifies this further by directly exposing values:

foreach ($orders as $order) {
  processOrder($order);
}

Both emphasize readability and limit scope of control variables like $i.

array_walk()

To abstract away array operations into reusuable callbacks, array_walk() passes values into a closure:

array_walk($payments, function($payment) {    
   $paid = processPayment($payment);
   savePayment($paid);
});

This isolates payment handling out of loop code cleanly.

array_map()

Similarly, array_map() accepts a callback but returns a new modified array rather than affecting the input.

$names = [‘john‘, ‘jane‘, ‘bob‘];

$formatted = array_map(function($name) {
  return ucwords($name); 
}, $names); 

// $formatted = [‘John‘, ‘Jane‘, ‘Bob‘];

This maps strings to uppercase while keeping $names unchanged.

SPL Iterators

Finally, for advanced cases with specialized data objects, SPL iterators used by foreach internally enable powerful custom iterations:

class PaymentIterator extends IteratorIterator {

  public function __construct($payments) {
    parent::__construct(new ArrayIterator($payments)); 
  }

  public function current() {

    $payment = parent::current(); 

    // Transform payment

    return $payment;
  }

}

$iterator = new PaymentIterator($payments);

foreach ($iterator as $payment) {
  // Use transformed payment  
}

Here we craft a custom iterator handing work during iteration internally.

Many more strategies cater to unique modern use cases – the possibilities are endless!

Final Thoughts

While each() enjoyed favor offering array iteration capabilities to early PHP developers, languages evolve along with better design patterns and data handling needs.

As PHP matured to support richer programming models through native syntax and robust extensions, each() remained clinging to its simplistic roots. Hitting walls with arrays growing in dimension and complexity across larger systems, the community eventually parted ways.

But even as support ends with removal from the core language, understanding the function‘s signatures, return values and integration tactics still proves useful when maintaining legacy systems.

For greenfield development however, this guide covered far more reliable modern options that avoid iteration pitfalls, encapsulate logic and provide readable data access. By mastering these more versatile alternatives, engineers gain tools enabling them to create the next generation of high-scale PHP applications.

So while we bid farewell to this old friend, take comfort that brighter pastures lay ahead – and the core DNA of each() still perseveres powering iterations internally across backends everywhere!

Similar Posts