PHP array_filter พร้อมอาร์กิวเมนต์


109

ฉันมีรหัสต่อไปนี้:

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

ที่ฉันสามารถใช้เพื่อกรองอาร์เรย์เช่นนี้:

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

ฉันจะเพิ่มอาร์กิวเมนต์ให้กับ lower_than_10 เพื่อให้ยอมรับหมายเลขที่จะตรวจสอบได้อย่างไร เช่นถ้าฉันมีสิ่งนี้:

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

จะเรียกมันจาก array_filter ผ่าน 10 ถึง $ num หรือหมายเลขอะไรก็ได้

คำตอบ:


64

เป็นอีกทางเลือกหนึ่งของการแก้ปัญหาของ @ Charles โดยใช้การปิดคุณสามารถดูตัวอย่างได้ในความคิดเห็นในหน้าเอกสาร แนวคิดคือคุณสร้างวัตถุด้วยสถานะที่ต้องการ ( $num) และวิธีการเรียกกลับ (ใช้$iเป็นอาร์กิวเมนต์):

class LowerThanFilter {
        private $num;

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

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

การใช้งาน ( สาธิต ):

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

ในฐานะที่เป็น sidenote ขณะนี้คุณสามารถแทนที่LowerThanFilterด้วยทั่วไปมากขึ้นNumericComparisonFilterด้วยวิธีการเช่นisLower, isGreater, isEqualฯลฯ เพียงความคิด - และสาธิต ...


วิธีแก้ปัญหาที่ดี เพื่อประโยชน์ในการบำรุงรักษาโค้ดอาจช่วยแก้ไขคลาสเพื่อรองรับการเรียกใช้เมธอดที่อ่านได้มากขึ้นเช่นกัน: $ match = $ myobj-> ArraySelect (Array ('from' => $ arr, 'where' => $ foo, 'lessthan' => 12))
dreftymac

ฉันไม่ใช่ผู้เชี่ยวชาญด้าน php ดังนั้นนี่อาจเป็นคำถามที่ชัดเจน แต่คุณจะส่งอาร์เรย์ไปยัง array_filter และยังคงใช้งานได้อย่างไร เอกสารไม่เคยพูดถึงเรื่องนี้ยกเว้นความคิดเห็นของใครบางคน
Nicola Pedretti

1
@NicolaPedretti ฉันคิดว่าคุณกำลังพูดถึงข้อโต้แย้งวินาทีที่array_filter? มันเป็นเพียงcallable; ในกรณีข้างต้นตรงกับ "Type 3: Object method call" array(<instance>, <method-name>):, cf. PHP: Callbacks / Callables - คู่มือการใช้งาน
jensgram

น่าสนใจ. มันรู้สึกแฮ็คสำหรับฉันจริงๆ การส่งผ่านวิธีนี้โดยตรงดูเหมือนง่ายกว่า
Nicola Pedretti

@nicolapedretti ฉันไม่ได้สัมผัส PHP มาหลายปีแล้ว ตอนนี้ส่วนใหญ่รู้สึก
แฮ็

264

หากคุณใช้ php 5.3 ขึ้นไปคุณสามารถใช้การปิดเพื่อทำให้โค้ดของคุณง่ายขึ้น:

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

12
ไม่ทราบว่าคุณสามารถใช้useคำนี้เพื่อให้แลมบ์ดามีพารามิเตอร์เพิ่มเติมได้ ขอบคุณสำหรับคำใบ้ที่มีค่า! :)
Julio María Meca Hansen

15
นี่คือทางออกที่ดีที่สุดในความคิดของฉัน มันง่ายและตรงประเด็น เป็นเรื่องน่าเสียดายที่ PHP ไม่อนุญาตให้ฟังก์ชันที่ไม่ระบุตัวตนใช้ตัวแปรที่ประกาศในขอบเขตหลักเช่นในจาวาสคริปต์
NadiaFaya

4
มีประโยชน์สวยหรูสั้น +1
Grokking

7
ผมเชื่อว่านี่ควรจะเป็นทางออกที่ได้รับการยอมรับในขณะที่มันเป็นเพียงคนเดียวที่ตอบคำถาม: "วิธีการที่สามารถเพิ่มข้อโต้แย้ง array_filter" คำตอบอื่น ๆ กำลังให้เส้นทางอื่นสำหรับผลลัพธ์เดียวกันโดยใช้การปิดหรือคลาส
tao

ขอบคุณครับ. สมบูรณ์
อรุณจิตต์ RS

37

ใน PHP 5.3 ขึ้นไปคุณสามารถใช้การปิด :

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
ขอบคุณสำหรับการแก้ปัญหามันเรียบร้อย แต่ฉันมี php 5.2 บนเซิร์ฟเวอร์ดังนั้นฉันต้องใช้ jensgram ของ :)
pistacchio

ใน php <5.3 คุณสามารถใช้create_function().
Decent Dabbler

3
create_function()โดยพื้นฐานแล้วeval()มีชื่ออื่นและชั่วร้ายพอ ๆ การใช้มันควรจะหมดกำลังใจ วิธีแก้ปัญหาตามคลาสที่แปลกประหลาดที่ให้ไว้ในคำตอบที่ยอมรับนั้นเป็นทางออกที่ดีกว่าการใช้create_function()ในกรณีนี้
Charles

20

หากคุณต้องการส่งผ่านพารามิเตอร์หลายตัวไปยังฟังก์ชันคุณสามารถต่อท้ายคำสั่งใช้โดยใช้ ",":

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

14

ในส่วนขยายของคำตอบjensgramคุณสามารถเพิ่มเวทมนตร์ได้มากขึ้นโดยใช้__invoke()วิธีมายากล

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

ซึ่งจะช่วยให้คุณสามารถทำได้

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


}

สิ่งนี้ช่วยให้คุณกรองรายการในอาร์เรย์หลายมิติ:

$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')) );
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.