PHP array_filter dengan argumen

108

Saya memiliki kode berikut:

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

yang bisa saya gunakan untuk memfilter array seperti ini:

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

Bagaimana cara menambahkan argumen ke lower_than_10 sehingga ia juga menerima nomor untuk diperiksa? Seperti, jika saya punya ini:

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

bagaimana memanggilnya dari array_filter melewati 10 ke $ num atau nomor berapa pun?

pistacchio.dll
sumber

Jawaban:

64

Sebagai alternatif dari solusi @ Charles menggunakan closure , Anda sebenarnya dapat menemukan contohnya di komentar di halaman dokumentasi. Idenya adalah Anda membuat objek dengan state yang diinginkan ( $num) dan metode callback (mengambil $isebagai argumen):

class LowerThanFilter {
        private $num;

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

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

Penggunaan ( demo ):

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

Sebagai catatan pinggir, kini Anda dapat mengganti LowerThanFilterdengan yang lebih umum NumericComparisonFilterdengan metode seperti isLower, isGreater, isEqualdll Hanya pikiran - dan demo ...

jensgram.dll
sumber
Solusi yang bagus. Demi kode yang dapat dipelihara, mungkin membantu untuk memodifikasi kelas untuk mendukung pemanggilan metode yang lebih mudah dibaca juga: $ match = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac
Saya bukan php savy, jadi mungkin ini adalah pertanyaan yang jelas, tapi bagaimana Anda bisa mengirimkan array ke array_filter dan tetap membuatnya berfungsi? dokumentasi tidak pernah membicarakan hal ini, kecuali komentar seseorang.
Nicola Pedretti
1
@NicolaPedretti Saya berasumsi Anda sedang berbicara tentang argumen detik array_filter? Ini hanyalah sebuah callable; dalam kasus di atas yang cocok dengan "Tipe 3: Panggilan metode objek" array(<instance>, <method-name>):, lih. PHP: Callbacks / Callables - Manual .
jensgram
Menarik. Rasanya benar-benar hacky bagi saya. Meneruskan metode secara langsung tampaknya lebih intuitif.
Nicola Pedretti
@nicolapedretti Saya belum pernah menyentuh PHP selama beberapa tahun. Sekarang sebagian besar terasa hacky bagi saya :)
jensgram
261

jika Anda menggunakan php 5.3 ke atas, Anda dapat menggunakan closure untuk menyederhanakan kode Anda:

$NUM = 5;
$items = array(1, 4, 5, 8, 0, 6);
$filteredItems = array_filter($items, function($elem) use($NUM){
    return $elem < $NUM;
});
ZHENJiNG LiANG
sumber
12
Tidak tahu Anda dapat menggunakan usekata tersebut untuk memberikan lambda parameter tambahan. Terima kasih atas petunjuk yang sangat berharga! :)
Julio María Meca Hansen
15
Ini menurut saya solusi terbaik. Sederhana dan langsung ke intinya. Sayangnya PHP tidak mengizinkan fungsi anonim untuk menggunakan variabel yang dideklarasikan dalam lingkup induk, seperti di javascript.
NadiaFaya
4
Berguna, elegan, pendek, +1
Grokking
7
Saya percaya ini harus menjadi solusi yang diterima, karena ini adalah satu-satunya yang menjawab pertanyaan: "bagaimana menambahkan argumen ke array_filter" . Jawaban lain memberikan rute alternatif ke hasil yang sama, baik menggunakan closure atau class.
tao
Terima kasih Bung. Sempurna
Arunjith RS
36

Di PHP 5.3 atau lebih baik, Anda dapat menggunakan closure :

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
sumber
1
terima kasih untuk solusinya, ini rapi, tetapi saya memiliki php 5.2 di server, jadi saya terikat untuk menggunakan jensgram's :)
pistacchio
Di php <5.3 Anda bisa menggunakan create_function().
Decent Dabbler
3
create_function()pada dasarnya eval()dengan nama lain, dan sama jahatnya. Menggunakannya harus dicegah. Solusi berbasis kelas yang aneh yang diberikan dalam jawaban yang diterima adalah solusi yang lebih baik daripada menggunakan create_function()dalam kasus ini.
Charles
20

jika Anda membutuhkan beberapa parameter untuk diteruskan ke fungsi, Anda dapat menambahkannya ke pernyataan use menggunakan ",":

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

Sebagai tambahan untuk jawaban jensgram Anda dapat menambahkan lebih banyak keajaiban dengan menggunakan __invoke()metode ajaib.

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

Ini akan memungkinkan Anda untuk melakukannya

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


}

Ini memungkinkan Anda untuk memfilter item dalam array multidimensi:

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