PHP array_filter з аргументами


108

У мене є такий код:

function lower_than_10($i) {
    return ($i < 10);
}

що я можу використовувати для фільтрування такого масиву:

$arr = array(7, 8, 9, 10, 11, 12, 13);
$new_arr = array_filter($arr, 'lower_than_10');

Як я можу додати аргументи до нижнього_на_10, щоб він також прийняв номер, на який слід перевірити? Мовляв, якщо у мене є таке:

function lower_than($i, $num) {
    return ($i < $num);
}

як викликати його з array_filter, що проходить від 10 до $ num або будь-якого числа?

Відповіді:


64

Як альтернатива рішенню @ Чарльза, що використовує закриття , ви можете знайти приклад у коментарях на сторінці документації. Ідея полягає в тому, що ви створюєте об'єкт із потрібним станом ( $num) та методом зворотного виклику (беручи $iза аргумент):

class LowerThanFilter {
        private $num;

        function __construct($num) {
                $this->num = $num;
        }

        function isLower($i) {
                return $i < $this->num;
        }
}

Використання ( демонстрація ):

$arr = array(7, 8, 9, 10, 11, 12, 13);
$matches = array_filter($arr, array(new LowerThanFilter(12), 'isLower'));
print_r($matches);

Як Зауваження, тепер ви можете замінити LowerThanFilterз більш загальним NumericComparisonFilterз методами , як isLower, isGreater, і isEqualт.д. Просто думка - і демо ...


Гарне вирішення. Заради збереженого коду це може допомогти змінити клас, щоб він підтримував і більш читабельні виклики методів: $ match = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac

Я не прихильник php, тому, можливо, це очевидне питання, але як ви можете передати масив array_filter і все-таки змусити його працювати? документація ніколи про це не говорить, крім когось коментаря.
Nicola Pedretti

1
@NicolaPedretti Я припускаю, що ви говорите про секундовий аргумент array_filter? Це просто a callable; у наведеному вище випадку відповідність "Тип 3: Виклик методу об'єкта":, array(<instance>, <method-name>)пор. PHP: зворотні дзвінки / дзвінки - керівництво .
jensgram

Цікаво. Мені це справді хакі. Передача методу безпосередньо здається більш інтуїтивно зрозумілою.
Nicola Pedretti

@nicolapedretti Я не торкався PHP вже кілька років. На сьогоднішній день більшість з них відчуває себе
хитким

261

якщо ви використовуєте php 5.3 і вище, ви можете використовувати закриття для спрощення коду:

$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
    return $elem < $NUM;
});

12
Не знав, що ви можете використовувати це useслово, щоб надати лямбда додаткові параметри. Дякуємо за такий цінний натяк! :)
Хуліо Марія Мека Хансен

15
Це, на мій погляд, найкраще рішення. Це просто і до речі. Прикро, що PHP не дозволяє анонімним функціям використовувати змінні, оголошені в батьківській області, як у JavaScript.
NadiaFaya

4
Корисний, елегантний, короткий, +1
Grokking

7
Я вважаю, що це має бути прийнятим рішенням, оскільки це єдине, що відповідає на питання: "як можна додати аргументи до array_filter" . Інші відповіді пропонують альтернативні маршрути до того ж результату, використовуючи або закриття, або класи.
дао

Дякую, чувак. Ідеально
Arunjith RS

36

У PHP 5.3 або вище, ви можете використовувати закриття :

function create_lower_than($number = 10) {
// The "use" here binds $number to the function at declare time.
// This means that whenever $number appears inside the anonymous
// function, it will have the value it had when the anonymous
// function was declared.
    return function($test) use($number) { return $test < $number; };
}

// We created this with a ten by default.  Let's test.
$lt_10 = create_lower_than();
var_dump($lt_10(9)); // True
var_dump($lt_10(10)); // False
var_dump($lt_10(11)); // False

// Let's try a specific value.
$lt_15 = create_lower_than(15);
var_dump($lt_15(13)); // True
var_dump($lt_15(14)); // True
var_dump($lt_15(15)); // False
var_dump($lt_15(16)); // False

// The creation of the less-than-15 hasn't disrupted our less-than-10:
var_dump($lt_10(9)); // Still true
var_dump($lt_10(10)); // Still false
var_dump($lt_10(11)); // Still false

// We can simply pass the anonymous function anywhere that a
// 'callback' PHP type is expected, such as in array_filter:
$arr = array(7, 8, 9, 10, 11, 12, 13);
$new_arr = array_filter($arr, $lt_10);
print_r($new_arr);

1
дякую за рішення, це акуратно, але у мене на сервері є php 5.2, тому я зобов’язаний використовувати jensgram's :)
фісташка

У php <5.3 ви можете використовувати create_function().
Гідний даблер

3
create_function()в основному eval()з іншим ім'ям, і так само зло. Використовувати його слід не рекомендувати. Нерозумне рішення на основі класу, наведене у прийнятій відповіді, є кращим рішенням, ніж використання create_function()в цьому випадку.
Чарльз

20

якщо вам потрібно передати кілька параметрів у функцію, ви можете додати їх до оператора use, використовуючи ",":

$r = array_filter($anArray, function($anElement) use ($a, $b, $c){
    //function body where you may use $anElement, $a, $b and $c
});

14

На додаток до відповіді на jensgram ви можете додати ще трохи магії за допомогою __invoke()магічного методу.

class LowerThanFilter {
    private $num;

    public function __construct($num) {
        $this->num = $num;
    }

    public function isLower($i) {
        return $i < $this->num;
    }

    function __invoke($i) {
        return $this->isLower($i);
    }
}

Це дозволить вам зробити

$arr = array(7, 8, 9, 10, 11, 12, 13);
$matches = array_filter($arr, new LowerThanFilter(12));
print_r($matches);

5
class ArraySearcher{

const OPERATOR_EQUALS = '==';
const OPERATOR_GREATERTHAN = '>';
const OPERATOR_LOWERTHAN = '<'; 
const OPERATOR_NOT = '!=';      

private $_field;
private $_operation;
private $_val;

public function __construct($field,$operation,$num) {
    $this->_field = $field;
    $this->_operation = $operation;
    $this->_val = $num;
}


function __invoke($i) {
    switch($this->_operation){
        case '==':
            return $i[$this->_field] == $this->_val;
        break;

        case '>':
            return $i[$this->_field] > $this->_val;
        break;

        case '<':
            return $i[$this->_field] < $this->_val;
        break;

        case '!=':
            return $i[$this->_field] != $this->_val;
        break;
    }
}


}

Це дозволяє фільтрувати елементи в багатовимірних масивах:

$users = array();
$users[] = array('email' => 'user1@email.com','name' => 'Robert');
$users[] = array('email' => 'user2@email.com','name' => 'Carl');
$users[] = array('email' => 'user3@email.com','name' => 'Robert');

//Print all users called 'Robert'
print_r( array_filter($users, new ArraySearcher('name',ArraySearcher::OPERATOR_EQUALS,'Robert')) );
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.