PHP array_filter z argumentami

108

Mam następujący kod:

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

których mogę użyć do filtrowania tablicy takiej jak ta:

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

Jak mogę dodać argumenty do lower_than_10, aby akceptował również liczbę do sprawdzenia? Na przykład, jeśli mam to:

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

jak to nazwać z array_filter, przekazując 10 do $ num lub jakąkolwiek liczbę?

pistacchio
źródło

Odpowiedzi:

64

Jako alternatywę dla rozwiązania @ Charles używającego domknięć , możesz faktycznie znaleźć przykład w komentarzach na stronie dokumentacji. Chodzi o to, aby utworzyć obiekt z żądanym stanem ( $num) i metodą wywołania zwrotnego (przyjmując $ijako argument):

class LowerThanFilter {
        private $num;

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

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

Użycie ( demo ):

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

Jako marginesie, można teraz zastąpić LowerThanFilterz bardziej rodzajowe NumericComparisonFilterz metod, takich jak isLower, isGreater, isEqualitp tylko myśl - i demo ...

jensgram
źródło
Dobre obejście. Ze względu na łatwy w utrzymaniu kod może pomóc zmodyfikowanie klasy, aby obsługiwała również bardziej czytelne wywołania metod: $ match = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac
Nie jestem fanem php, więc może to oczywiste pytanie, ale jak możesz przekazać tablicę do array_filter i nadal działać? dokumentacja nigdy o tym nie mówi, z wyjątkiem czyjegoś komentarza.
Nicola Pedretti
1
@NicolaPedretti Zakładam, że mówisz o argumentach sekund array_filter? To po prostu callable; w powyższym przypadku dopasowanie „Typ 3: Wywołanie metody obiektu” array(<instance>, <method-name>):, por. PHP: Callbacks / Callables - Manual .
jensgram
Ciekawy. To dla mnie naprawdę dziwne. Podanie metody bezpośrednio wydaje się bardziej intuicyjne.
Nicola Pedretti
@nicolapedretti Od kilku lat nie dotykałem PHP. W tej chwili większość z nich wydaje mi się
zepsuta
261

jeśli używasz php 5.3 i nowszych, możesz użyć zamknięcia, aby uprościć swój kod:

$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
    return $elem < $NUM;
});
ZHENJiNG LiANG
źródło
12
Nie wiedziałem, że możesz użyć tego usesłowa, aby nadać lambdzie dodatkowe parametry. Dzięki za tak cenną wskazówkę! :)
Julio María Meca Hansen
15
To moim zdaniem najlepsze rozwiązanie. To proste i na temat. Szkoda, że ​​PHP nie pozwala anonimowym funkcjom na używanie zmiennych zadeklarowanych w zakresie nadrzędnym, jak w javascript.
NadiaFaya,
4
Przydatne, eleganckie, krótkie, +1
Grokking
7
Uważam, że powinno to być przyjęte rozwiązanie, ponieważ jako jedyne odpowiada na pytanie: „jak dodać argumenty do array_filter” . Inne odpowiedzi podają alternatywne ścieżki do tego samego wyniku, przy użyciu zamknięcia lub klas.
tao
Dzięki stary. Idealnie
Arunjith RS
37

W PHP 5.3 lub nowszym możesz użyć zamknięcia :

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);
Charles
źródło
1
dzięki za rozwiązanie, jest fajnie, ale mam php 5.2 na serwerze, więc jestem zobowiązany do korzystania z jensgrama :)
pistacchio
W php <5.3 możesz użyć create_function().
Godny Dabbler
3
create_function()ma w zasadzie eval()inne imię i jest równie zła. Używanie go powinno być odradzane. Zwariowane obejście oparte na klasach podane w zaakceptowanej odpowiedzi jest lepszym rozwiązaniem niż użycie create_function()w tym przypadku.
Charles,
20

jeśli potrzebujesz wielu parametrów do przekazania do funkcji, możesz dołączyć je do instrukcji use za pomocą ",":

$r = array_filter($anArray, function($anElement) use ($a, $b, $c){
    //function body where you may use $anElement, $a, $b and $c
});
Mar Bar
źródło
14

W uzupełnieniu do odpowiedzi jensgram możesz dodać więcej magii za pomocą __invoke()magicznej metody.

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);
    }
}

To pozwoli ci to zrobić

$arr = array(7, 8, 9, 10, 11, 12, 13);
$matches = array_filter($arr, new LowerThanFilter(12));
print_r($matches);
Stefan Gehrig
źródło
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;
    }
}


}

Pozwala to filtrować elementy w tablicach wielowymiarowych:

$users = array();
$users[] = array('email' => '[email protected]','name' => 'Robert');
$users[] = array('email' => '[email protected]','name' => 'Carl');
$users[] = array('email' => '[email protected]','name' => 'Robert');

//Print all users called 'Robert'
print_r( array_filter($users, new ArraySearcher('name',ArraySearcher::OPERATOR_EQUALS,'Robert')) );
Marcos Basualdo
źródło