PHP array_filter con argomenti


108

Ho il codice seguente:

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

che posso usare per filtrare un array come questo:

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

Come posso aggiungere argomenti a lower_than_10 in modo che accetti anche il numero da confrontare? Ad esempio, se ho questo:

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

come chiamarlo da array_filter passando 10 a $ num o qualsiasi altro numero?

Risposte:


64

In alternativa alla soluzione di @ Charles che utilizza le chiusure , puoi effettivamente trovare un esempio nei commenti nella pagina della documentazione. L'idea è di creare un oggetto con lo stato desiderato ( $num) e il metodo di callback (prendendo $icome argomento):

class LowerThanFilter {
        private $num;

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

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

Utilizzo ( demo ):

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

Come sidenote, è ora possibile sostituire LowerThanFiltercon un più generico NumericComparisonFiltercon metodi come isLower, isGreater, isEqualecc Basta un pensiero - e di una demo ...


Buona soluzione alternativa. Per motivi di codice gestibile, potrebbe essere utile modificare la classe per supportare anche chiamate di metodi più leggibili: $ match = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac

Non sono un esperto di php, quindi forse questa è una domanda ovvia, ma come puoi passare un array a array_filter e farlo funzionare? la documentazione non parla mai di questo, tranne che per il commento di qualcuno.
Nicola Pedretti

1
@NicolaPedretti presumo tu stia parlando del secondo argomento a array_filter? È semplicemente un callable; nel caso precedente corrispondente a "Tipo 3: chiamata al metodo dell'oggetto" array(<instance>, <method-name>):, cfr. PHP: Callbacks / Callables - Manuale .
jensgram

Interessante. Mi sembra davvero hacky. Passare direttamente il metodo sembra più intuitivo.
Nicola Pedretti

@nicolapedretti Non tocco PHP da diversi anni. Ormai la maggior parte mi sembra hacky :)
jensgram

261

se usi php 5.3 e versioni successive, puoi usare la chiusura per semplificare il tuo codice:

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

12
Non sapevo che potresti usare la useparola per fornire al lambda parametri extra. Grazie per un suggerimento così prezioso! :)
Julio María Meca Hansen

15
Questa è secondo me la soluzione migliore. È semplice e al punto. È un peccato che PHP non consenta alle funzioni anonime di utilizzare variabili dichiarate nell'ambito genitore, come in javascript.
NadiaFaya

4
Utile, elegante, breve, +1
Grokking

7
Credo che questa dovrebbe essere la soluzione accettata, in quanto è l'unica che risponde alla domanda: "come si possono aggiungere argomenti a array_filter" . Le altre risposte forniscono percorsi alternativi per lo stesso risultato, utilizzando la chiusura o le classi.
tao

Grazie amico. Perfetto
Arunjith RS

36

In PHP 5.3 o superiore, puoi utilizzare una chiusura :

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
grazie per la soluzione, è pulito, ma ho php 5.2 sul server, quindi sono obbligato a usare jensgram's :)
pistacchio

In php <5.3 potresti usare create_function().
Decent Dabbler

3
create_function()è fondamentalmente eval()con un altro nome, ed è altrettanto malvagio. Usarlo dovrebbe essere scoraggiato. La stravagante soluzione alternativa basata sulla classe fornita nella risposta accettata è una soluzione migliore rispetto all'utilizzo create_function()in questo caso.
Charles

20

se hai bisogno di più parametri da passare alla funzione, puoi aggiungerli all'istruzione use usando ",":

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

14

In estensione alla risposta jensgram puoi aggiungere un po 'più di magia usando il __invoke()metodo magico.

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

Questo ti permetterà di farlo

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


}

Ciò consente di filtrare gli elementi in array multidimensionali:

$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')) );
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.