Navigation

Php

How to Filter Arrays with array_filter()

Remove unwanted elements from PHP arrays using array_filter() with custom callback functions for data cleaning and validation.

Table Of Contents

The Solution

Array filtering removes elements that don't meet specific criteria while preserving the original keys. PHP's array_filter() function applies a callback to each element, keeping only those where the callback returns a truthy value, making it perfect for data validation and cleanup.

<?php

// Basic filtering - remove empty values
$data = ['apple', '', 'banana', null, 'cherry', 0, false];
$filtered = array_filter($data);
// Result: ['apple', 'banana', 'cherry'] (removes '', null, 0, false)

// Custom callback function
$numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// Filter even numbers
$evenNumbers = array_filter($numbers, function($n) {
    return $n % 2 === 0;
});
// Result: [2, 4, 6, 8, 10] (keys preserved: [1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 10])

// Filter odd numbers using arrow function
$oddNumbers = array_filter($numbers, fn($n) => $n % 2 === 1);
// Result: [1, 3, 5, 7, 9]

// Filter by value and key
$products = [
    'laptop' => 999,
    'mouse' => 25,
    'keyboard' => 75,
    'monitor' => 300,
    'webcam' => 120
];

// Filter expensive products (>100)
$expensiveProducts = array_filter($products, fn($price) => $price > 100);
// Result: ['laptop' => 999, 'monitor' => 300, 'webcam' => 120]

// Filter using both key and value
$itemsStartingWithM = array_filter($products, function($price, $name) {
    return str_starts_with($name, 'm');
}, ARRAY_FILTER_USE_BOTH);
// Result: ['mouse' => 25, 'monitor' => 300]

// Filter by key only
$longNames = array_filter($products, function($key) {
    return strlen($key) > 5;
}, ARRAY_FILTER_USE_KEY);
// Result: ['laptop' => 999, 'keyboard' => 75, 'monitor' => 300]

// Real-world examples

// Filter valid email addresses
$emails = [
    'john@example.com',
    'invalid-email',
    'jane@domain.org',
    '',
    'admin@test.co.uk',
    'not.an.email'
];

$validEmails = array_filter($emails, function($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
});
// Result: valid email addresses only

// Filter user data
$users = [
    ['name' => 'John', 'age' => 25, 'active' => true],
    ['name' => 'Jane', 'age' => 17, 'active' => true],
    ['name' => 'Bob', 'age' => 30, 'active' => false],
    ['name' => 'Alice', 'age' => 22, 'active' => true]
];

// Filter active adult users
$activeAdults = array_filter($users, function($user) {
    return $user['active'] && $user['age'] >= 18;
});

// Filter by multiple conditions
$conditions = [
    'min_age' => 20,
    'status' => 'active',
    'department' => 'engineering'
];

$employees = [
    ['name' => 'John', 'age' => 25, 'status' => 'active', 'department' => 'engineering'],
    ['name' => 'Jane', 'age' => 19, 'status' => 'active', 'department' => 'engineering'],
    ['name' => 'Bob', 'age' => 30, 'status' => 'inactive', 'department' => 'engineering'],
    ['name' => 'Alice', 'age' => 28, 'status' => 'active', 'department' => 'marketing']
];

function filterByConditions(array $items, array $conditions): array {
    return array_filter($items, function($item) use ($conditions) {
        foreach ($conditions as $field => $value) {
            if ($field === 'min_age') {
                if ($item['age'] < $value) return false;
            } else {
                if ($item[$field] !== $value) return false;
            }
        }
        return true;
    });
}

$filteredEmployees = filterByConditions($employees, $conditions);

// Filter file types
$files = [
    'document.pdf',
    'image.jpg',
    'script.php',
    'data.csv',
    'photo.png',
    'backup.sql'
];

function filterFilesByExtension(array $files, array $allowedExtensions): array {
    return array_filter($files, function($file) use ($allowedExtensions) {
        $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
        return in_array($extension, $allowedExtensions);
    });
}

$imageFiles = filterFilesByExtension($files, ['jpg', 'png', 'gif']);
$documentFiles = filterFilesByExtension($files, ['pdf', 'doc', 'docx']);

// Remove duplicates while filtering
function filterUnique(array $array, callable $keyGenerator): array {
    $seen = [];
    return array_filter($array, function($item) use ($keyGenerator, &$seen) {
        $key = $keyGenerator($item);
        if (in_array($key, $seen)) {
            return false;
        }
        $seen[] = $key;
        return true;
    });
}

$duplicateUsers = [
    ['email' => 'john@example.com', 'name' => 'John'],
    ['email' => 'jane@example.com', 'name' => 'Jane'],
    ['email' => 'john@example.com', 'name' => 'Johnny'],
    ['email' => 'bob@example.com', 'name' => 'Bob']
];

$uniqueByEmail = filterUnique($duplicateUsers, fn($user) => $user['email']);

// Filter with count tracking
function filterWithStats(array $array, callable $callback): array {
    $stats = ['passed' => 0, 'filtered' => 0];
    
    $result = array_filter($array, function($item) use ($callback, &$stats) {
        if ($callback($item)) {
            $stats['passed']++;
            return true;
        } else {
            $stats['filtered']++;
            return false;
        }
    });
    
    return ['data' => $result, 'stats' => $stats];
}

$scores = [85, 92, 67, 78, 95, 43, 88, 56, 91, 74];
$passingResults = filterWithStats($scores, fn($score) => $score >= 70);

echo "Passing scores: " . count($passingResults['data']) . "\n";
echo "Failed scores: " . $passingResults['stats']['filtered'] . "\n";

// Chain filtering operations
$rawData = [
    ['name' => 'Product A', 'price' => 99.99, 'category' => 'electronics', 'in_stock' => true],
    ['name' => 'Product B', 'price' => 149.99, 'category' => 'electronics', 'in_stock' => false],
    ['name' => 'Product C', 'price' => 29.99, 'category' => 'books', 'in_stock' => true],
    ['name' => 'Product D', 'price' => 199.99, 'category' => 'electronics', 'in_stock' => true]
];

// Chain multiple filters
$availableElectronics = array_filter(
    array_filter($rawData, fn($p) => $p['category'] === 'electronics'),
    fn($p) => $p['in_stock']
);

$affordableElectronics = array_filter($availableElectronics, fn($p) => $p['price'] < 150);

// Preserve or reset array keys
$numbersWithGaps = [0 => 10, 1 => 20, 2 => 30, 3 => 40, 4 => 50];
$filtered = array_filter($numbersWithGaps, fn($n) => $n > 25);
// Result has gaps: [2 => 30, 3 => 40, 4 => 50]

$reindexed = array_values($filtered);
// Result: [0 => 30, 1 => 40, 2 => 50]

// Performance tip: use early returns for complex filters
function isValidUser(array $user): bool {
    if (empty($user['email'])) return false;
    if ($user['age'] < 18) return false;
    if (!$user['verified']) return false;
    if (empty($user['name'])) return false;
    
    return true;
}

$validUsers = array_filter($users, 'isValidUser');

// Usage examples
echo "Valid emails: " . count($validEmails) . "\n";
echo "Active adults: " . count($activeAdults) . "\n";
echo "Image files: " . implode(', ', $imageFiles) . "\n";
echo "Unique users: " . count($uniqueByEmail) . "\n";
echo "Affordable electronics: " . count($affordableElectronics) . "\n";

Explanation

array_filter() provides three filtering modes: by value (default), by key (ARRAY_FILTER_USE_KEY), or by both (ARRAY_FILTER_USE_BOTH). The callback function receives the appropriate parameters based on the mode and should return true to keep the element or false to remove it.

The function preserves original array keys, which is useful for maintaining relationships but can create gaps in numeric arrays. Use array_values() afterward if you need sequential numeric keys.

Critical for data validation, user input sanitization, search filtering, and any scenario where you need to extract specific elements based on criteria. Combine with other array functions for powerful data processing pipelines.

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Php