PHP Fundamentals

Advanced Array Techniques

13 min Lesson 14 of 45

Advanced Array Manipulation Techniques

Now that you understand basic array operations and functions, let's explore advanced techniques that will help you write more elegant and efficient PHP code. These patterns are commonly used in professional applications.

Note: Advanced array techniques combine multiple operations to solve complex problems elegantly. They're essential for data processing, API handling, and business logic.

Array Destructuring and Unpacking

List Assignment (Array Destructuring)

<?php // Basic destructuring $colors = ["red", "green", "blue"]; list($first, $second, $third) = $colors; echo $first; // red echo $second; // green // Short syntax (PHP 7.1+) [$r, $g, $b] = $colors; echo "$r, $g, $b"; // Skip elements [$first, , $third] = $colors; echo "$first and $third"; // red and blue // With associative arrays $person = ["name" => "John", "age" => 30, "city" => "NYC"]; ["name" => $name, "age" => $age] = $person; echo "$name is $age years old"; // Nested destructuring $data = ["user" => ["name" => "Alice", "email" => "alice@example.com"]]; ["user" => ["name" => $userName, "email" => $userEmail]] = $data; ?>

Spread Operator (PHP 7.4+)

<?php // Unpacking arrays in function calls $numbers = [1, 2, 3]; function sum($a, $b, $c) { return $a + $b + $c; } echo sum(...$numbers); // 6 // Combining arrays $arr1 = [1, 2, 3]; $arr2 = [4, 5, 6]; $combined = [...$arr1, ...$arr2]; print_r($combined); // [1, 2, 3, 4, 5, 6] // Adding elements while unpacking $extended = [0, ...$arr1, 99, ...$arr2, 100]; print_r($extended); // [0, 1, 2, 3, 99, 4, 5, 6, 100] // With associative arrays (PHP 8.1+) $defaults = ["color" => "blue", "size" => "M"]; $custom = ["size" => "L", "style" => "casual"]; $merged = [...$defaults, ...$custom]; print_r($merged); ?>
Tip: The spread operator (...) is cleaner and often more efficient than array_merge() for combining arrays.

Advanced Filtering and Mapping

Chaining Array Operations

<?php $products = [ ["name" => "Laptop", "price" => 1200, "category" => "electronics"], ["name" => "Phone", "price" => 800, "category" => "electronics"], ["name" => "Desk", "price" => 350, "category" => "furniture"], ["name" => "Chair", "price" => 200, "category" => "furniture"], ["name" => "Monitor", "price" => 400, "category" => "electronics"] ]; // Chain: Filter electronics, map to names, sort $electronicsNames = array_values( array_map( function($product) { return $product["name"]; }, array_filter($products, function($p) { return $p["category"] === "electronics"; }) ) ); sort($electronicsNames); print_r($electronicsNames); // ["Laptop", "Monitor", "Phone"] ?>

Array Walk and Walk Recursive

<?php // array_walk - Apply function to each element (modifies in place) $prices = [100, 200, 300]; array_walk($prices, function(&$price) { $price = $price * 1.1; // Add 10% tax }); print_r($prices); // [110, 220, 330] // With key and additional data $products = ["laptop" => 1000, "phone" => 500]; array_walk($products, function(&$price, $name, $discount) { $price = $price * (1 - $discount); echo "$name: $$price<br>"; }, 0.1); // 10% discount // array_walk_recursive - For nested arrays $data = [ "user" => ["name" => "john", "email" => "JOHN@EXAMPLE.COM"], "settings" => ["theme" => "DARK", "lang" => "EN"] ]; array_walk_recursive($data, function(&$value) { if (is_string($value)) { $value = strtolower($value); } }); print_r($data); ?>
Warning: array_walk() modifies the original array. Use &$value to modify by reference.

Multidimensional Array Operations

Sorting Multidimensional Arrays

<?php $students = [ ["name" => "Alice", "grade" => 85, "age" => 20], ["name" => "Bob", "grade" => 92, "age" => 19], ["name" => "Charlie", "grade" => 78, "age" => 21], ["name" => "Diana", "grade" => 92, "age" => 18] ]; // Sort by grade (descending) usort($students, function($a, $b) { return $b["grade"] - $a["grade"]; }); // Sort by multiple fields (grade desc, then age asc) usort($students, function($a, $b) { if ($a["grade"] === $b["grade"]) { return $a["age"] - $b["age"]; } return $b["grade"] - $a["grade"]; }); // Using spaceship operator (PHP 7+) usort($students, function($a, $b) { return [$b["grade"], $a["age"]] <=> [$a["grade"], $b["age"]]; }); print_r($students); ?>

Grouping and Indexing

<?php $orders = [ ["id" => 1, "customer" => "John", "total" => 100], ["id" => 2, "customer" => "Jane", "total" => 150], ["id" => 3, "customer" => "John", "total" => 200], ["id" => 4, "customer" => "Bob", "total" => 80] ]; // Group by customer $grouped = []; foreach ($orders as $order) { $grouped[$order["customer"]][] = $order; } print_r($grouped); // Index by ID for quick lookup $indexed = array_column($orders, null, "id"); print_r($indexed); // [1 => [...], 2 => [...], ...] // Sum totals by customer $totals = []; foreach ($orders as $order) { $customer = $order["customer"]; $totals[$customer] = ($totals[$customer] ?? 0) + $order["total"]; } print_r($totals); // ["John" => 300, "Jane" => 150, "Bob" => 80] ?>

Array Recursion and Flattening

Flatten Nested Arrays

<?php // Recursive flatten function function flattenArray($array) { $result = []; foreach ($array as $item) { if (is_array($item)) { $result = array_merge($result, flattenArray($item)); } else { $result[] = $item; } } return $result; } $nested = [1, [2, 3], [4, [5, 6]], 7]; $flat = flattenArray($nested); print_r($flat); // [1, 2, 3, 4, 5, 6, 7] // Using array_merge and spread (limited depth) $flat = array_merge(...$nested); // Works for 1 level // Flatten with keys function flattenWithKeys($array, $prefix = "") { $result = []; foreach ($array as $key => $value) { $newKey = $prefix ? "{$prefix}.{$key}" : $key; if (is_array($value)) { $result = array_merge($result, flattenWithKeys($value, $newKey)); } else { $result[$newKey] = $value; } } return $result; } $data = [ "user" => [ "name" => "John", "address" => ["city" => "NYC", "zip" => "10001"] ] ]; print_r(flattenWithKeys($data)); // ["user.name" => "John", "user.address.city" => "NYC", ...] ?>

Array Pipeline Pattern

Create reusable data transformation pipelines:

<?php // Pipeline helper function function pipeline($data, ...$operations) { return array_reduce($operations, function($carry, $operation) { return $operation($carry); }, $data); } // Define reusable operations $filterAdults = fn($users) => array_filter($users, fn($u) => $u["age"] >= 18); $extractNames = fn($users) => array_map(fn($u) => $u["name"], $users); $sortAlpha = fn($names) => (function($arr) { sort($arr); return $arr; })($names); // Use the pipeline $users = [ ["name" => "Alice", "age" => 25], ["name" => "Bob", "age" => 17], ["name" => "Charlie", "age" => 30] ]; $result = pipeline( $users, $filterAdults, $extractNames, $sortAlpha ); print_r($result); // ["Alice", "Charlie"] ?>
Tip: Pipeline patterns make complex data transformations readable and testable. Each step is isolated and reusable.

Array Memoization and Caching

<?php // Memoization function function memoize($func) { $cache = []; return function(...$args) use ($func, &$cache) { $key = serialize($args); if (!isset($cache[$key])) { $cache[$key] = $func(...$args); } return $cache[$key]; }; } // Expensive operation function fibonacci($n) { if ($n <= 1) return $n; return fibonacci($n - 1) + fibonacci($n - 2); } // Memoized version $fibMemo = memoize("fibonacci"); echo $fibMemo(10); // Fast on repeated calls echo $fibMemo(10); // Returns cached result ?>

Array Partitioning

<?php // Partition array into two groups based on condition function partition($array, $callback) { $passed = []; $failed = []; foreach ($array as $key => $value) { if ($callback($value, $key)) { $passed[$key] = $value; } else { $failed[$key] = $value; } } return [$passed, $failed]; } $numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]; [$even, $odd] = partition($numbers, fn($n) => $n % 2 === 0); print_r($even); // [2, 4, 6, 8] print_r($odd); // [1, 3, 5, 7, 9] // Real-world example: Partition orders by status $orders = [ ["id" => 1, "paid" => true, "amount" => 100], ["id" => 2, "paid" => false, "amount" => 50], ["id" => 3, "paid" => true, "amount" => 200] ]; [$paid, $unpaid] = partition($orders, fn($o) => $o["paid"]); ?>

Array Diffing and Patching

<?php // Recursive array diff function arrayDiffRecursive($array1, $array2) { $diff = []; foreach ($array1 as $key => $value) { if (!array_key_exists($key, $array2)) { $diff[$key] = $value; } elseif (is_array($value) && is_array($array2[$key])) { $recursiveDiff = arrayDiffRecursive($value, $array2[$key]); if (!empty($recursiveDiff)) { $diff[$key] = $recursiveDiff; } } elseif ($value !== $array2[$key]) { $diff[$key] = $value; } } return $diff; } $old = [ "name" => "John", "settings" => ["theme" => "light", "lang" => "en"] ]; $new = [ "name" => "John", "settings" => ["theme" => "dark", "lang" => "en"] ]; $changes = arrayDiffRecursive($new, $old); print_r($changes); // ["settings" => ["theme" => "dark"]] ?>

Array Validation Patterns

<?php // Validate array structure function validateStructure($data, $rules) { $errors = []; foreach ($rules as $key => $rule) { // Check required if ($rule["required"] && !isset($data[$key])) { $errors[$key][] = "Field is required"; continue; } if (!isset($data[$key])) continue; $value = $data[$key]; // Check type if (isset($rule["type"]) && gettype($value) !== $rule["type"]) { $errors[$key][] = "Invalid type"; } // Check min/max for numbers if (isset($rule["min"]) && $value < $rule["min"]) { $errors[$key][] = "Value too small"; } if (isset($rule["max"]) && $value > $rule["max"]) { $errors[$key][] = "Value too large"; } // Custom validator if (isset($rule["validator"]) && !$rule["validator"]($value)) { $errors[$key][] = "Validation failed"; } } return $errors; } // Usage $data = ["name" => "John", "age" => 15, "email" => "invalid"]; $rules = [ "name" => ["required" => true, "type" => "string"], "age" => ["required" => true, "type" => "integer", "min" => 18], "email" => [ "required" => true, "validator" => fn($v) => filter_var($v, FILTER_VALIDATE_EMAIL) ] ]; $errors = validateStructure($data, $rules); print_r($errors); ?>

Performance Optimization Techniques

<?php // Use array_key_exists for large arrays with null values $largeArray = array_fill_keys(range(0, 10000), null); // Faster if (array_key_exists(5000, $largeArray)) { } // Slower (returns false for null values) if (isset($largeArray[5000])) { } // Use array_column for extracting data $users = /* large array of user objects */; // Faster $emails = array_column($users, "email"); // Slower $emails = array_map(fn($u) => $u["email"], $users); // Pre-allocate arrays when size is known $result = array_fill(0, 1000, null); for ($i = 0; $i < 1000; $i++) { $result[$i] = $i * 2; } // Use generators for large datasets function getNumbers($max) { for ($i = 0; $i < $max; $i++) { yield $i; } } foreach (getNumbers(1000000) as $number) { // Process without loading all into memory } ?>
Exercise:
  1. Create a pipeline that filters, transforms, and sorts an array of products
  2. Implement a function that groups an array of orders by month and calculates monthly totals
  3. Write a recursive function to find all paths in a nested array structure
  4. Create a function that validates and sanitizes user input using array rules
  5. Implement an array caching mechanism that expires after a certain time

Real-World Pattern: Data Transformation

<?php // Transform API response to application format function transformUsers($apiResponse) { return pipeline( $apiResponse["data"]["users"] ?? [], fn($users) => array_filter($users, fn($u) => $u["active"]), fn($users) => array_map(function($user) { return [ "id" => $user["user_id"], "name" => $user["first_name"] . " " . $user["last_name"], "email" => strtolower($user["email"]), "roles" => array_map("strtolower", $user["roles"] ?? []) ]; }, $users), fn($users) => array_column($users, null, "id") ); } ?>

Best Practices

  • Use pipeline patterns for complex transformations
  • Leverage PHP 7.4+ spread operator for cleaner code
  • Use arrow functions (fn) for concise callbacks
  • Implement memoization for expensive array operations
  • Use generators for large datasets to save memory
  • Validate array structures before processing
  • Consider performance implications of recursive operations
  • Use spaceship operator (<=>) for complex sorting
Warning: Recursive operations can be memory-intensive. Always consider maximum nesting depth and add limits for safety.

Summary

In this lesson, you mastered:

  • Array destructuring and spread operator for cleaner code
  • Advanced filtering, mapping, and chaining techniques
  • Multidimensional array sorting and grouping
  • Array recursion, flattening, and traversal
  • Pipeline patterns for data transformation
  • Memoization and caching strategies
  • Array partitioning and validation patterns
  • Performance optimization techniques

These advanced techniques will help you write more elegant, efficient, and maintainable PHP code. Practice combining them to solve real-world problems!

ES
Edrees Salih
23 hours ago

We are still cooking the magic in the way!