PHP array_filter mit Argumenten

108

Ich habe folgenden Code:

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

mit denen ich ein Array wie folgt filtern kann:

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

Wie kann ich lower_than_10 Argumente hinzufügen, damit es auch die Nummer akzeptiert, gegen die geprüft werden soll? Wie, wenn ich das habe:

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

Wie rufe ich es von array_filter auf, indem ich 10 an $ num oder eine andere Nummer übergebe?

Pistacchio
quelle

Antworten:

64

Als Alternative zu @ Charles ' Lösung mit Verschlüssen finden Sie ein Beispiel in den Kommentaren auf der Dokumentationsseite. Die Idee ist, dass Sie ein Objekt mit dem gewünschten Status ( $num) und der Rückrufmethode ( $ials Argument) erstellen :

class LowerThanFilter {
        private $num;

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

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

Verwendung ( Demo ):

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

Als Nebenbei bemerkt, können Sie jetzt ersetzen LowerThanFiltermit einem allgemeineren NumericComparisonFiltermit Methoden wie isLower, isGreater, isEqualusw. Nur einen Gedanken - und eine Demo ...

Jensgramm
quelle
Gute Problemumgehung. Aus Gründen des wartbaren Codes kann es hilfreich sein, die Klasse so zu ändern, dass auch besser lesbare Methodenaufrufe unterstützt werden: $ match = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac
Ich bin kein PHP-Kenner, also ist dies vielleicht eine offensichtliche Frage, aber wie können Sie ein Array an array_filter übergeben und es trotzdem zum Laufen bringen? In der Dokumentation wird nie darüber gesprochen, außer in einem Kommentar von jemandem.
Nicola Pedretti
1
@NicolaPedretti Ich nehme an, Sie sprechen über das Sekunden-Argument zu array_filter? Es ist einfach ein callable; im obigen Fall passend zu "Typ 3: Objektmethodenaufruf": array(<instance>, <method-name>)vgl. PHP: Callbacks / Callables - Handbuch .
Jensgramm
Interessant. Es fühlt sich für mich wirklich hackig an. Das direkte Übergeben der Methode erscheint intuitiver.
Nicola Pedretti
@nicolapedretti Ich habe PHP seit mehreren Jahren nicht mehr berührt. Inzwischen fühlt sich das meiste für mich hackig an :)
Jensgramm
259

Wenn Sie PHP 5.3 und höher verwenden, können Sie Closure verwenden , um Ihren Code zu vereinfachen:

$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
    return $elem < $NUM;
});
ZHENJiNG LiANG
quelle
12
Ich wusste nicht, dass Sie das useWort verwenden können, um dem Lambda zusätzliche Parameter bereitzustellen. Danke für diesen wertvollen Hinweis! :)
Julio María Meca Hansen
15
Dies ist meiner Meinung nach die beste Lösung. Es ist einfach und auf den Punkt. Es ist eine Schande, dass PHP anonymen Funktionen nicht erlaubt, Variablen zu verwenden, die im übergeordneten Bereich deklariert sind, wie in Javascript.
NadiaFaya
4
Nützlich, elegant, kurz, +1
Grokking
7
Ich glaube, dies sollte die akzeptierte Lösung sein, da dies die einzige ist, die die Frage beantwortet: "Wie können Argumente zu array_filter hinzugefügt werden?" . Die anderen Antworten bieten alternative Routen zum gleichen Ergebnis, entweder mit Abschluss oder mit Klassen.
Tao
Danke Alter. Perfekt
Arunjith RS
36

In PHP 5.3 oder besser können Sie einen Abschluss verwenden :

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
quelle
1
danke für die lösung, es ist ordentlich, aber ich habe php 5.2 auf dem server, also bin ich verpflichtet, jensgram's zu verwenden :)
pistacchio
In PHP <5.3 könnten Sie verwenden create_function().
Anständiger Dabbler
3
create_function()ist im Grunde eval()mit einem anderen Namen und ist genauso böse. Von der Verwendung sollte abgeraten werden. Die verrückte klassenbasierte Problemumgehung in der akzeptierten Antwort ist eine bessere Lösung als create_function()in diesem Fall.
Charles
20

Wenn mehrere Parameter an die Funktion übergeben werden müssen, können Sie sie mit "," an die use-Anweisung anhängen:

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

In Erweiterung zur Jensgramm- Antwort können Sie mithilfe der __invoke()Magie-Methode etwas mehr Magie hinzufügen .

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

Auf diese Weise können Sie dies tun

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


}

Auf diese Weise können Sie Elemente in mehrdimensionalen Arrays filtern:

$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
quelle