PHP array_filter avec arguments

108

J'ai le code suivant:

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

que je peux utiliser pour filtrer un tableau comme celui-ci:

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

Comment puis-je ajouter des arguments à lower_than_10 pour qu'il accepte également le nombre à vérifier? Comme, si j'ai ceci:

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

comment l'appeler de array_filter en passant 10 à $ num ou n'importe quel nombre?

pistache
la source

Réponses:

64

Comme alternative à la solution de @ Charles utilisant des fermetures , vous pouvez en fait trouver un exemple dans les commentaires sur la page de documentation. L'idée est que vous créez un objet avec l'état souhaité ( $num) et la méthode de rappel (en prenant $icomme argument):

class LowerThanFilter {
        private $num;

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

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

Utilisation ( démo ):

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

En tant que sidenote, vous pouvez remplacer LowerThanFilterpar un plus générique NumericComparisonFilteravec des méthodes comme isLower, isGreater, isEqualetc. Juste une pensée - et une démo ...

Jensgram
la source
Bonne solution de contournement. Pour des raisons de code maintenable, il peut être utile de modifier la classe pour prendre en charge également des appels de méthode plus lisibles: $ matches = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac
Je ne suis pas un expert en php, alors peut-être que c'est une question évidente, mais comment pouvez-vous passer un tableau à array_filter et le faire fonctionner? la documentation n'en parle jamais, à l'exception du commentaire de quelqu'un.
Nicola Pedretti
1
@NicolaPedretti Je suppose que vous parlez de l'argument des secondes array_filter? C'est simplement un callable; dans le cas ci-dessus correspondant à "Type 3: Appel de méthode objet" array(<instance>, <method-name>):, cf. PHP: Callbacks / Callables - Manuel .
jensgram
Intéressant. Cela me semble vraiment piraté. Passer la méthode directement semble plus intuitif.
Nicola Pedretti
@nicolapedretti Je n'ai pas touché PHP depuis plusieurs années. À présent, la plupart des choses me
semblent piratées
261

si vous utilisez php 5.3 et supérieur, vous pouvez utiliser la fermeture pour simplifier votre code:

$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
    return $elem < $NUM;
});
ZHENJiNG LiANG
la source
12
Je ne savais pas que vous pouviez utiliser le usemot pour fournir au lambda des paramètres supplémentaires. Merci pour un si précieux indice! :)
Julio María Meca Hansen
15
C'est à mon avis la meilleure solution. C'est simple et pertinent. C'est dommage que PHP n'autorise pas les fonctions anonymes à utiliser des variables déclarées dans la portée parent, comme en javascript.
NadiaFaya
4
Utile, élégant, court, +1
Grokking
7
Je pense que cela devrait être la solution acceptée, car c'est la seule qui répond à la question: "comment ajouter des arguments à array_filter" . Les autres réponses fournissent des itinéraires alternatifs au même résultat, en utilisant soit la fermeture, soit les classes.
tao
Merci mec. Parfait
Arunjith RS
36

En PHP 5.3 ou supérieur, vous pouvez utiliser une fermeture :

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
la source
1
merci pour la solution, c'est chouette, mais j'ai php 5.2 sur le serveur, donc je suis obligé d'utiliser jensgram's :)
pistacchio
En php <5.3, vous pouvez utiliser create_function().
Decent Dabbler
3
create_function()est fondamentalement eval()avec un autre nom, et est tout aussi mauvais. Son utilisation doit être découragée. La solution de contournement farfelue basée sur les classes donnée dans la réponse acceptée est une meilleure solution que l'utilisation create_function()dans ce cas.
Charles
20

si vous avez besoin de plusieurs paramètres à transmettre à la fonction, vous pouvez les ajouter à l'instruction use en utilisant ",":

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

En extension de jensgram answer, vous pouvez ajouter un peu plus de magie en utilisant la __invoke()méthode magique.

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

Cela vous permettra de faire

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


}

Cela vous permet de filtrer les éléments dans des tableaux multidimensionnels:

$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
la source