146 votes

PHP array_filter avec des arguments

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 ? Par exemple, si j'ai ceci :

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

comment l'appeler depuis array_filter en passant 10 à $num ou tout autre nombre ?

355voto

ZHENJiNG LiANG Points 449

Si vous utilisez php 5.3 et plus, vous pouvez utiliser 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;
});

17 votes

Je ne savais pas que vous pouviez utiliser le use pour fournir à la lambda des paramètres supplémentaires. Merci pour ce précieux conseil :)

23 votes

C'est à mon avis la meilleure solution. Elle est simple et va droit au but. C'est dommage que PHP ne permette pas aux fonctions anonymes d'utiliser les variables déclarées dans la portée parent, comme en javascript.

4 votes

Utile, élégant, court, +1

75voto

jensgram Points 18047

Comme alternative à la solution de @Charles solution utilisant des fermetures vous pouvez 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 $i comme argument) :

class LowerThanFilter {
        private $num;

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

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

Utilisation ( Démonstration ):

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

À titre d'information, vous pouvez maintenant remplacer l'option LowerThanFilter avec une version plus générique NumericComparisonFilter avec des méthodes comme isLower , isGreater , isEqual etc. C'est juste une idée - et un Démo ...

0 votes

Bonne solution de contournement. Dans l'intérêt d'un code facile à maintenir, il pourrait être utile de modifier la classe pour qu'elle prenne en charge des appels de méthode plus lisibles : $matches = $myobj->ArraySelect( Array('from'=>$arr, 'where'=>$foo, 'lessthan'=>12 ) )

1 votes

Je ne suis pas un expert en php, donc peut-être que c'est une question évidente, mais comment peut-on passer un tableau à array_filter et faire en sorte que cela fonctionne ? la documentation ne parle jamais de cela, sauf dans le commentaire de quelqu'un.

1 votes

@NicolaPedretti Je suppose que vous parlez de l'argument des secondes pour array_filter ? Il s'agit simplement d'un callable ; dans le cas ci-dessus correspondant à "Type 3 : Appel de méthode d'objet" : array(<instance>, <method-name>) , cf. PHP : Callbacks / Callables - Manuel .

39voto

Charles Points 33585

En PHP 5.3 ou plus, vous pouvez utiliser une balise 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);

1 votes

Merci pour la solution, c'est chouette, mais j'ai php 5.2 sur le serveur, donc je suis obligé d'utiliser celle de jensgram :)

0 votes

En php < 5.3, vous pouvez utiliser create_function() .

3 votes

create_function() est en fait eval() avec un autre nom, et est tout aussi maléfique. 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 de create_function() dans ce cas.

14voto

Stefan Gehrig Points 47227

Dans le prolongement de jensgram vous pouvez ajouter un peu plus de magie en utilisant la réponse __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);

5voto

Marcos Basualdo Points 51
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 des éléments dans des tableaux multidimensionnels :

$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')) );

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X