PHP: Функции

Теория: Фильтрация

Следующая операция называется фильтрация. В PHP она выполняется с помощью функции array_filter, а в других языках ее называют просто filter или select.

Понятие «фильтрация» интуитивно понятно каждому человеку. Мы пьем фильтрованную воду и фильтруем то, что говорим. В программировании практически то же самое. Фильтрация по отношению к коллекции означает, что мы отбираем из нее только те элементы, которые удовлетворяют условию.

Возьмем наших многострадальных пользователей и выберем тех, кто старше 10 лет:

<?php

$users = [
    ['name' => 'Igor', 'age' => 19],
    ['name' => 'Danil', 'age' => 1],
    ['name' => 'Vovan', 'age' => 4],
    ['name' => 'Matvey', 'age' => 16],
];

$result = [];
foreach ($users as $user) {
    if ($user['age'] > 10) {
        $result[] = $user;
    }
}
print_r($result);
// => Array
// (
//     [0] => Array
//         (
//             [name] => Igor
//             [age] => 19
//         )
//
//     [1] => Array
//         (
//             [name] => Matvey
//             [age] => 16
//         )
//
// )

Фильтрация встречается так же часто, как отображение, а возможно и чаще. Общая схема кода при фильтрации практически такая же, как и в отображении. Отличается только пара ключевых моментов:

  • Фильтрация возвращает коллекцию либо того же размера (если ничего не было отфильтровано), либо меньшего. Она может вернуть даже пустую коллекцию, если ни один из элементов не подошел
  • Фильтрация всегда возвращает исходные элементы. Она никогда не делает отображение. Если на вход фильтрации поступил список пользователей, то список пользователей будет и на выходе

Как работает filter

Теперь посмотрим, как выглядит фильтрация при использовании функции высшего порядка array_filter:

<?php

// Порядок аргументов обратный
// Сначала идет коллекция, а затем — функция
// $user – это элемент массива $users
$filteredUsers = array_filter($users, fn($user) => $user['age'] > 10);

В отличие от array_map, переданная в array_filter функция должна быть предикатом. Другими словами, она должна вернуть true или false для каждого элемента коллекции. Значение, которое возвращается никак не используется. Оно всего лишь говорит о том, стоит ли включать текущий элемент в итоговый массив. Новички часто делают ошибку на этом этапе и начинают возвращать из фильтра то, что они бы хотели увидеть в результирующем массиве. На самом деле, для этого надо применять array_map.

Перейдем к реализации:

<?php

function myFilter($coll, callable $callback)
{
    $result = [];
    foreach ($coll as $key => $item) {
        // Предикат используется только для проверки
        // Внутрь $callback по очереди передается каждый элемент коллекции $coll
        if ($callback($item)) {
            // В результат всегда добавляется элемент исходной коллекции
            $result[$key] = $item;
        }
    }
    return $result;
}

Обратите внимание, что array_filter сохраняет ключи. При работе с индексированными массивами такое поведение нежелательно, поэтому придется использовать функцию array_values для сброса порядка.

Рекомендуемые программы