วิธีส่งอาร์กิวเมนต์จำนวนตัวแปรไปยังฟังก์ชัน PHP


115

ฉันมีฟังก์ชัน PHP ที่รับอาร์กิวเมนต์จำนวนตัวแปร (โดยใช้func_num_args()และfunc_get_args()) แต่จำนวนอาร์กิวเมนต์ที่ฉันต้องการส่งผ่านฟังก์ชันนั้นขึ้นอยู่กับความยาวของอาร์เรย์ มีวิธีการเรียกใช้ฟังก์ชัน PHP ด้วยอาร์กิวเมนต์กี่ตัวแปรหรือไม่?


1
ตรวจสอบคำตอบของฉันเพื่อเรียนรู้เกี่ยวกับตัวดำเนินการ Splat ใน php5.6 ใหม่: stackoverflow.com/a/23163963/1090562
Salvador Dali

คำตอบ:


132

หากคุณมีอาร์กิวเมนต์ในอาร์เรย์คุณอาจสนใจcall_user_func_arrayฟังก์ชัน

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

องค์ประกอบของอาร์เรย์ที่คุณส่งผ่านจะได้รับจากฟังก์ชันของคุณเป็นพารามิเตอร์ที่แตกต่างกัน


ตัวอย่างเช่นหากคุณมีฟังก์ชันนี้:

function test() {
  var_dump(func_num_args());
  var_dump(func_get_args());
}

คุณสามารถบรรจุพารามิเตอร์ของคุณลงในอาร์เรย์ได้ดังนี้:

$params = array(
  10,
  'glop',
  'test',
);

จากนั้นเรียกใช้ฟังก์ชัน:

call_user_func_array('test', $params);

รหัสนี้จะส่งออก:

int 3

array
  0 => int 10
  1 => string 'glop' (length=4)
  2 => string 'test' (length=4)

กล่าวคือ 3 พารามิเตอร์; เหมือนกับ iof ฟังก์ชันถูกเรียกด้วยวิธีนี้:

test(10, 'glop', 'test');

1
ใช่ขอบคุณ. call_user_func_array () เป็นฟังก์ชันที่ฉันกำลังมองหา
nohat

เป็นไปได้ไหมที่จะใช้ call_user_func_array () กับการเรียกใช้ object method?
nohat

6
@nohat: ยินดีต้อนรับครับ :-) ;; เกี่ยวกับการใช้วิธีการของวัตถุ: ใช่คุณสามารถใช้อาร์เรย์ ($ obj, 'methodName') เป็นพารามิเตอร์แรก ;; จริงๆแล้วคุณสามารถส่ง "การเรียกกลับ" ที่คุณต้องการไปยังฟังก์ชันนั้นได้ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการโทรกลับโปรดดูที่php.net/callback#language.types.callback
Pascal MARTIN

58

ตอนนี้สามารถทำได้ด้วย PHP 5.6.xโดยใช้ตัวดำเนินการ ... (หรือที่เรียกว่าตัวดำเนินการ Splat ในบางภาษา):

ตัวอย่าง:

function addDateIntervalsToDateTime( DateTime $dt, DateInterval ...$intervals )
{
    foreach ( $intervals as $interval ) {
        $dt->add( $interval );
    }
    return $dt;
}

addDateIntervaslToDateTime( new DateTime, new DateInterval( 'P1D' ), 
        new DateInterval( 'P4D' ), new DateInterval( 'P10D' ) );

1
พิมพ์รายการอาร์กิวเมนต์ตัวแปรเป็นคุณลักษณะที่นำมาใช้ในPHP 7
Daniele Orlando

46

ในPhp 5.6ใหม่คุณสามารถใช้... operatorแทนการใช้func_get_args().

ดังนั้นเมื่อใช้สิ่งนี้คุณจะได้รับพารามิเตอร์ทั้งหมดที่คุณส่งผ่าน:

function manyVars(...$params) {
   var_dump($params);
}

3
ข้อมูลเพิ่มเติมที่นี่: php.net/manual/en/…
fracz

จากลิงก์ @fracz OP กำลังพยายามสร้าง "ฟังก์ชันตัวแปร"
Nathan Arthur

40

ตั้งแต่PHP 5.6สามารถระบุรายการอาร์กิวเมนต์ตัวแปรกับตัว...ดำเนินการได้

function do_something($first, ...$all_the_others)
{
    var_dump($first);
    var_dump($all_the_others);
}

do_something('this goes in first', 2, 3, 4, 5);

#> string(18) "this goes in first"
#>
#> array(4) {
#>   [0]=>
#>   int(2)
#>   [1]=>
#>   int(3)
#>   [2]=>
#>   int(4)
#>   [3]=>
#>   int(5)
#> }

ดังที่คุณเห็นตัว...ดำเนินการรวบรวมรายการตัวแปรของอาร์กิวเมนต์ในอาร์เรย์

หากคุณต้องการส่งผ่านอาร์กิวเมนต์ของตัวแปรไปยังฟังก์ชันอื่นสิ่ง...นี้ยังสามารถช่วยคุณได้

function do_something($first, ...$all_the_others)
{
    do_something_else($first, ...$all_the_others);
    // Which is translated to:
    // do_something_else('this goes in first', 2, 3, 4, 5);
}

ตั้งแต่PHP 7รายการตัวแปรของอาร์กิวเมนต์สามารถบังคับให้เป็นประเภทเดียวกันทั้งหมดได้เช่นกัน

function do_something($first, int ...$all_the_others) { /**/ }

11

สำหรับผู้ที่กำลังมองหาวิธีดำเนินการดังต่อไปนี้$object->method:

call_user_func_array(array($object, 'method_name'), $array);

ฉันประสบความสำเร็จกับสิ่งนี้ในฟังก์ชันการสร้างที่เรียกตัวแปร method_name พร้อมพารามิเตอร์ตัวแปร


2
คุณยังสามารถใช้$object->method_name(...$array);
Yoann Kergall

ต่อไปหากต้องการส่งต่อให้ใช้$object->method_name(&...$args);
Fabien Haddadi

4

คุณสามารถเรียกมัน

function test(){        
     print_r(func_get_args());
}

test("blah");
test("blah","blah");

เอาท์พุท:

อาร์เรย์ ([0] => blah) อาร์เรย์ ([0] => blah [1] => blah)


หากฉันเข้าใจ OP อย่างถูกต้องปัญหาคือไม่ได้รับพารามิเตอร์ แต่เรียกใช้ฟังก์ชันด้วยพารามิเตอร์จำนวนตัวแปร
Pascal MARTIN

1
ฉันไม่เข้าใจ OP อย่างถูกต้องแล้ว อาร์เรย์จะเป็นหนทางไปอย่างแน่นอน จากนั้นอีกครั้งเขาสามารถส่งอาร์เรย์เข้าสู่การทดสอบได้โดยตรง () ไม่?
Donnie C

1
การส่งอาร์เรย์อาจเป็นวิธีแก้ปัญหาได้เช่นกัน - ถ้าฉันเข้าใจถูกต้อง ^^
Pascal MARTIN

1
คำถามเก่า แต่ fyi อาร์เรย์ทำงานได้ดี แต่การส่งผ่านอาร์กิวเมนต์จริงช่วยให้คุณใช้ค่าเริ่มต้นของ PHP สำหรับอาร์กิวเมนต์ว่างซึ่งช่วยประหยัดการตรวจสอบที่น่าเกลียดจำนวนมากเพื่อดูว่าอาร์เรย์มีค่าเฉพาะหรือไม่
Endophage

2

ฉันแปลกใจที่ไม่มีใครพูดถึงแค่การส่งผ่านและแยกอาร์เรย์ เช่น:

function add($arr){
    extract($arr, EXTR_REFS);
    return $one+$two;
}
$one = 1;
$two = 2;
echo add(compact('one', 'two')); // 3

ของหลักสูตรนี้ไม่ได้ให้ตรวจสอบการโต้แย้ง สำหรับสิ่งนั้นทุกคนสามารถใช้ฟังก์ชันคาดหวังของฉัน: https://gist.github.com/iautomation/8063fc78e9508ed427d5


1

อย่างไรก็ตามคำถามเก่า ๆ ฉันรู้ว่าไม่มีคำตอบใดที่จะตอบคำถามได้ดีจริงๆ

ฉันเพิ่งเล่นกับ php และโซลูชันมีลักษณะดังนี้:

function myFunction($requiredArgument, $optionalArgument = "default"){
   echo $requiredArgument . $optionalArgument;
}

ฟังก์ชั่นนี้สามารถทำได้สองอย่าง:

หากเรียกด้วยพารามิเตอร์ที่ต้องการเท่านั้น: myFunction("Hi") มันจะพิมพ์ "Hi default"

แต่ถ้ามันถูกเรียกด้วยพารามิเตอร์ทางเลือก: myFunction("Hi","me") มันจะพิมพ์ "สวัสดีฉัน";

ฉันหวังว่านี่จะช่วยทุกคนที่กำลังมองหาสิ่งนี้อยู่ระหว่างทาง


2
คุณไม่เข้าใจคำถาม OP กำลังถามเกี่ยวกับอาร์กิวเมนต์ที่เขาไม่จำเป็นต้องกำหนดอย่างชัดเจนในลายเซ็นของฟังก์ชันแต่เขายังสามารถส่งผ่านค่าเป็นอาร์กิวเมนต์ไปยังฟังก์ชันได้ ยกตัวอย่างเช่นลายเซ็นของฟังก์ชั่นไม่ได้มีใด ๆข้อโต้แย้งที่กำหนดไว้ (ไม่จำเป็นหรือไม่) แต่เมื่อเขาต้องการมัน OP สามารถส่งค่าที่แตกต่างกัน 45 เป็นข้อโต้แย้งที่จะฟังก์ชั่น
a20

0

นี่คือวิธีแก้ปัญหาโดยใช้วิธีมายากล __invoke

(ใช้ได้ตั้งแต่ php 5.3)

class Foo {
    public function __invoke($method=null, $args=[]){
        if($method){
            return call_user_func_array([$this, $method], $args);
        }
        return false;
    }

    public function methodName($arg1, $arg2, $arg3){

    }
}

จากภายในคลาสเดียวกัน:

$this('methodName', ['arg1', 'arg2', 'arg3']);

จากตัวอย่างของวัตถุ:

$obj = new Foo;
$obj('methodName', ['arg1', 'arg2', 'arg3'])

โดยทั่วไปแล้วจะใช้call_user_func_arrayตามที่ระบุไว้โดยคำตอบที่ได้รับการโหวตสูงสุดในปี 2009 บางทีอาจมีจุดที่ต้องห่อส่วนพิเศษไว้__invokeรอบ ๆ - แต่ฉันไม่เห็นมัน
a20
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.