We are still cooking the magic in the way!
PHP Fundamentals
Advanced Array Techniques
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:
- Create a pipeline that filters, transforms, and sorts an array of products
- Implement a function that groups an array of orders by month and calculates monthly totals
- Write a recursive function to find all paths in a nested array structure
- Create a function that validates and sanitizes user input using array rules
- 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!