ใช้อาร์กิวเมนต์เริ่มต้นในฟังก์ชั่น


177

ฉันสับสนเกี่ยวกับค่าเริ่มต้นสำหรับฟังก์ชั่น PHP ว่าฉันมีฟังก์ชั่นเช่นนี้:

function foo($blah, $x = "some value", $y = "some other value") {
    // code here!
}

ถ้าฉันต้องการใช้อาร์กิวเมนต์เริ่มต้นสำหรับ $ x และตั้งค่าอาร์กิวเมนต์อื่นสำหรับ $ y

ฉันกำลังทดลองกับวิธีที่แตกต่างกันและฉันก็สับสนมากขึ้น ตัวอย่างเช่นฉันลองสองสิ่งนี้:

foo("blah", null, "test");
foo("blah", "", "test");

แต่ทั้งสองอย่างนั้นไม่ส่งผลให้เกิดอาร์กิวเมนต์เริ่มต้นที่เหมาะสมสำหรับ $ x ฉันได้ลองตั้งชื่อตัวแปรแล้ว

foo("blah", $x, $y = "test");   

ฉันคาดหวังอย่างเต็มที่ว่าสิ่งนี้จะทำงาน แต่มันไม่ทำงานอย่างที่ฉันคาดไว้เลย ดูเหมือนว่าไม่ว่าฉันจะทำอะไรฉันจะต้องพิมพ์ท้ายด้วยการโต้เถียงเริ่มต้นทุกครั้งที่ฉันเรียกใช้ฟังก์ชัน และฉันต้องคิดถึงบางสิ่งที่ชัดเจน


68
คุณอาจไม่พลาดอะไรเลยนักพัฒนา PHP อาจพลาดสิ่งนี้ไป
Matti Virkkunen

นั่นเป็นคำถามที่น่าสนใจ ฉันไม่เคยมีความต้องการที่จะทำสิ่งนี้ตามที่คุณระบุเพราะฉันใช้ค่าเริ่มต้น args เพื่อขยายฟังก์ชั่นที่สืบทอดโดยโปรแกรมเมอร์อื่น ๆ เมื่อฉันไม่แน่ใจว่าสิ่งที่ขึ้นอยู่กับต้นฉบับ ฉันอยากรู้เกี่ยวกับคำตอบ
ไก่ชิง

3
หนึ่งในคำถามที่ดีที่สุดที่ฉันเคยเห็นในขณะ! คุณเคยลองทำสิ่งใดบ้างไหม? foo("blah", , "test");?
ผีของมาดาราระ

2
กฎคืออาร์กิวเมนต์เริ่มต้นสามารถติดตามอาร์กิวเมนต์ได้เท่านั้น นั่นคือคุณอาจมี foo ("blah") และ x, y เป็นค่าเริ่มต้นหรือ foo ("Blah", "xyz") และ y เป็นค่าเริ่มต้น
Mouse Mouse

1
พฤติกรรมที่คาดหวัง ดูส่วน "ค่าอาร์กิวเมนต์เริ่มต้น" ใน: php.net/manual/en/functions.arguments.php - ค่า null และสตริงว่างได้รับการยอมรับว่าเป็นอาร์กิวเมนต์ที่เกิดขึ้นจริงกับฟังก์ชั่น
jmdavalos

คำตอบ:


164

ฉันจะเสนอให้เปลี่ยนการประกาศฟังก์ชั่นดังต่อไปนี้เพื่อให้คุณสามารถทำสิ่งที่คุณต้องการ:

function foo($blah, $x = null, $y = null) {
    if (null === $x) {
        $x = "some value";
    }

    if (null === $y) {
        $y = "some other value";
    }

    code here!

}

ด้วยวิธีนี้คุณสามารถโทรออกfoo('blah', null, 'non-default y value');และใช้งานได้ตามที่คุณต้องการโดยพารามิเตอร์ที่สอง$xยังคงได้รับค่าเริ่มต้น

ด้วยวิธีนี้การส่งผ่านค่า Null หมายถึงคุณต้องการค่าเริ่มต้นสำหรับหนึ่งพารามิเตอร์เมื่อคุณต้องการแทนที่ค่าเริ่มต้นสำหรับพารามิเตอร์ที่ตามมา

ตามที่ระบุไว้ในคำตอบอื่น ๆ

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

หากฉันมีวิธีการที่สามารถยอมรับจำนวนพารามิเตอร์ที่แตกต่างกันและพารามิเตอร์ของประเภทที่แตกต่างกันฉันมักจะประกาศฟังก์ชั่นที่คล้ายกับคำตอบที่แสดงโดย Ryan P.

นี่เป็นอีกตัวอย่างหนึ่ง (นี่ไม่ได้ตอบคำถามของคุณ แต่เป็นข้อมูลที่หวังว่า:

public function __construct($params = null)
{
    if ($params instanceof SOMETHING) {
        // single parameter, of object type SOMETHING
    } else if (is_string($params)) {
        // single argument given as string
    } else if (is_array($params)) {
        // params could be an array of properties like array('x' => 'x1', 'y' => 'y1')
    } else if (func_num_args() == 3) {
        $args = func_get_args();

        // 3 parameters passed
    } else if (func_num_args() == 5) {
        $args = func_get_args();
        // 5 parameters passed
    } else {
        throw new InvalidArgumentException("Could not figure out parameters!");
    }
}

ทำไมไม่ใช่ $ x = isset ($ x) $ x: 'ค่าเริ่มต้น'; ?
zloctb

@zloctb นี่เป็นการตรวจสอบ null ที่สะอาดและสามารถอ่านได้ ดูเหมือนว่าเป็นค่ากำหนดของนักพัฒนาซอฟต์แวร์ $ x = isset ($ x) ใช่ไหม $ x: 'ค่าเริ่มต้น'; หรือ $ x = is_null ($ x)? 'ค่าเริ่มต้น': $ x; จะทำงานเช่นเดียวกับการแก้ปัญหานี้ มันเป็นตัวเลือกการตั้งค่าเกี่ยวกับการอ่านและการบำรุงรักษา
DeveloperWeeks

9
เพียงชี้แจงสำหรับผู้อ่านในอนาคต วิธีแก้ปัญหาแรกทำให้เห็นได้ชัดว่าเป็นไปไม่ได้ที่จะกำหนดnullค่าจริงให้กับพารามิเตอร์เนื่องจากทุกครั้งที่มันจะกำหนดค่าเริ่มต้น แม้ในกรณีที่คุณมีค่าพิเศษอื่น ๆ เมื่อคุณต้องการให้เป็นโมฆะจริง (เช่นเมื่อ $ x == "use_null" ทำให้ $ x = null) จากนั้นคุณจะไม่สามารถกำหนดค่าพิเศษเช่นค่าตามตัวอักษรของ พารามิเตอร์ (ในกรณีนี้สตริง "use_null") ดังนั้นเพียงให้แน่ใจว่าได้ใช้ "คีย์" ที่ไม่เหมือนใครซึ่งไม่เคยต้องการเมื่อคุณต้องการใช้ค่าเริ่มต้น (และคุณต้องการnullเป็นตัวเลือกที่ถูกต้อง)
DiegoDD

37

อาร์กิวเมนต์ที่เป็นทางเลือกจะใช้ได้เฉพาะเมื่อสิ้นสุดการเรียกใช้ฟังก์ชัน ไม่มีวิธีในการระบุค่าสำหรับ $ y ในฟังก์ชันของคุณโดยไม่ได้ระบุ $ x บางภาษารองรับสิ่งนี้ผ่านพารามิเตอร์ที่มีชื่อ (เช่น VB / C #) แต่ไม่ใช่ PHP

คุณสามารถเลียนแบบสิ่งนี้หากคุณใช้อาเรย์แบบเชื่อมโยงสำหรับพารามิเตอร์แทนการขัดแย้ง - เช่น

function foo(array $args = array()) {
    $x = !isset($args['x']) ? 'default x value' : $args['x'];
    $y = !isset($args['y']) ? 'default y value' : $args['y'];

    ...
}

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

foo(array('y' => 'my value'));

1
เงื่อนไขของคุณควรเป็นจริงisset($args['x'])เนื่องจากจะแทนที่สตริงว่างอาเรย์ว่างหรือfalseด้วยค่าเริ่มต้น
Tim Cooper

@TimCooper ฮ่า ๆ ฉันเปลี่ยนไปตามความเห็นแรกของคุณว่าควรเป็น '=== null' ไปและเปลี่ยนคำตอบของฉันในการใช้ isset แทนจากนั้นกลับมาเพื่อดูความคิดเห็นของคุณอีกด้วย : D
Ryan P

อ่า drat! ฉันไม่ชอบสิ่งนั้นเลย ... อืมคุณไม่มีทุกอย่างเลย ฉันคิดว่าฉันจะต้องเพิ่มความคิดอีกเล็กน้อยตามลำดับการโต้แย้งเริ่มต้นของฉัน ขอบคุณ!
renosis

น่าเสียดายที่คุณจะไม่สามารถกำหนดค่า null ให้กับคำตอบนี้ได้ นี่เป็นตัวเลือกที่ดีกว่า: $x = !array_key_exists('x',$args) ? 'default x value' : $args['x'];
Frank Forte

20

เป็นไปได้จริง:

foo( 'blah', (new ReflectionFunction('foo'))->getParameters()[1]->getDefaultValue(), 'test');

ไม่ว่าคุณจะต้องการทำเช่นนั้นเป็นอีกเรื่อง :)


UPDATE:

เหตุผลในการหลีกเลี่ยงการแก้ไขปัญหานี้คือ:

  • มันคือ (เนื้อหา) น่าเกลียด
  • มันมีค่าใช้จ่ายที่ชัดเจน
  • ในฐานะที่เป็นหลักฐานคำตอบอื่น ๆ มีทางเลือกอื่น

แต่มันจะมีประโยชน์จริง ๆ ในสถานการณ์ที่:

  • คุณไม่ต้องการ / ไม่สามารถเปลี่ยนฟังก์ชั่นดั้งเดิม

  • คุณสามารถเปลี่ยนฟังก์ชั่น แต่:

    • ใช้null(หรือเทียบเท่า) ไม่ใช่ตัวเลือก (ดูความคิดเห็นของ DiegoDD )
    • คุณไม่ต้องการไปด้วยการเชื่อมโยงหรือกับ func_num_args()
    • ชีวิตของคุณขึ้นอยู่กับการช่วยชีวิตสอง LOCs

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

แน่นอนถ้าคุณตั้งใจจะใช้มันในการวนซ้ำคุณควรจะได้รับค่าเริ่มต้นล่วงหน้า


1
อะไรคือเหตุผลที่ไม่ต้องการทำสิ่งนี้? ดูเหมือนว่ามีประโยชน์สวย
ไบรอัน

10
function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}

2
ฉันพลาดอะไรไปรึเปล่า? ดูเหมือนจะไม่ตอบคำถามเลย แต่มันมี 7 upvotes อาจเพิ่มคำอธิบายเล็กน้อยจะช่วยได้อย่างไร
Sean the Bean

3
@SeantheBean: จริงคำอธิบายจะดีกว่า แต่ประเด็นของเขาคือ: เนื่องจาก PHP ไม่มีชื่ออาร์กิวเมนต์ให้ใช้อาร์เรย์เชื่อมโยงเป็นพารามิเตอร์เดียว
MestreLion

1
การใช้ตัวอย่างที่ให้มาในคำถามจะเป็นประโยชน์มากกว่า$defaults = [ 'x' => 'some value', 'y' => 'some other value'];
Frank Forte

4

วิธีเดียวที่ฉันรู้ว่าทำคือการละเว้นพารามิเตอร์ วิธีเดียวที่จะละเว้นพารามิเตอร์คือการจัดเรียงรายการพารามิเตอร์ใหม่เพื่อให้สิ่งที่คุณต้องการละเว้นคือหลังจากพารามิเตอร์ที่คุณต้องตั้งค่า ตัวอย่างเช่น:

function foo($blah, $y = "some other value", $x = "some value")

จากนั้นคุณสามารถเรียก foo เช่น:

foo("blah", "test");

สิ่งนี้จะส่งผลให้:

$blah = "blah";
$y = "test";
$x = "some value";

3

ฉันเพิ่งมีปัญหานี้และพบคำถามและคำตอบนี้ ในขณะที่คำถามข้างต้นทำงานปัญหาคือพวกเขาไม่แสดงค่าเริ่มต้นให้กับ IDE ที่สนับสนุน (เช่น PHPStorm)

ป้อนคำอธิบายรูปภาพที่นี่

หากคุณใช้nullคุณจะไม่ทราบว่ามูลค่าจะเป็นอย่างไรถ้าคุณปล่อยให้ว่างไว้

วิธีที่ฉันชอบคือการใส่ค่าเริ่มต้นในการกำหนดฟังก์ชั่นด้วย:

protected function baseItemQuery(BoolQuery $boolQuery, $limit=1000, $sort = [], $offset = 0, $remove_dead=true)
{
    if ($limit===null) $limit =1000;
    if ($sort===null) $sort = [];
    if ($offset===null) $offset = 0;
    ...

ข้อแตกต่างเพียงอย่างเดียวคือฉันต้องตรวจสอบให้แน่ใจว่าพวกเขาเหมือนกัน - แต่ฉันคิดว่านั่นเป็นราคาขนาดเล็กที่ต้องจ่ายสำหรับความชัดเจนเพิ่มเติม


การใช้งาน ReflectionFunction ภายในตัวมันเองจะช่วยลดราคาได้!
SubjectDelta

2

คุณไม่สามารถทำได้โดยตรง แต่การเล่นซอโค้ดเล็กน้อยทำให้สามารถเลียนแบบได้

function foo($blah, $x = false, $y = false) {
  if (!$x) $x = "some value";
  if (!$y) $y = "some other value";

  // code
}

6
ที่จะทำงาน แต่ผมพบว่าใช้nullในกรณีนี้จะเป็นแนวคิด neater falseกว่า
TRiG

การเพิ่มความคิดเห็นของ TriG falseเป็นตัวเลือกที่เสี่ยงกว่าnullเพราะ php เป็นภาษาที่ไม่เข้มงวด จะเป็นจริงสำหรับปัจจัยการผลิตที่แตกต่างกันหลายประการที่อาจจะแปลกใจโปรแกรมเมอร์:!$x , ในขณะที่มีคุณสามารถใช้เป็นแบบทดสอบที่เข้มงวด 0''null!isset
ToolmakerSteve

1
<?php
function info($name="George",$age=18) {
echo "$name is $age years old.<br>";
}
info();     // prints default values(number of values = 2)
info("Nick");   // changes first default argument from George to Nick
info("Mark",17);    // changes both default arguments' values

?>

1

2 เซนต์ของฉันพร้อมโอเปอเรเตอร์การรวมตัวเป็นโมฆะ ?? (ตั้งแต่ PHP 7)

function foo($blah, $x = null, $y = null) {
    $varX = $x ?? 'Default value X';
    $varY = $y ?? 'Default value Y';
    // ...
}

คุณสามารถตรวจสอบตัวอย่างเพิ่มเติมเกี่ยวกับrepl.itของฉัน


0

ในกรณีนี้เมื่อวัตถุดีกว่า - เนื่องจากคุณสามารถตั้งค่าวัตถุของคุณให้ถือ x และ y ตั้งค่าเริ่มต้นเป็นต้น

วิธีการที่มีอาร์เรย์อยู่ใกล้กับการสร้างวัตถุ (อันที่จริงวัตถุคือพวงของพารามิเตอร์และฟังก์ชั่นที่จะทำงานกับวัตถุและฟังก์ชั่นการใช้อาร์เรย์จะทำงานกับพารามิเตอร์หลายกลุ่มพวง)

แน่นอนคุณสามารถทำเทคนิคเพื่อตั้งค่า null หรือสิ่งนี้เป็นค่าเริ่มต้น


0

คุณสามารถตรวจสอบว่าคุณมีสตริงว่างเปล่าเป็นอาร์กิวเมนต์เพื่อให้คุณสามารถโทรเช่น:

foo('blah', "", 'non-default y value', null);

ด้านล่างฟังก์ชั่น:

function foo($blah, $x = null, $y = null, $z = null) {
    if (null === $x || "" === $x) {
        $x = "some value";
    }

    if (null === $y || "" === $y) {
        $y = "some other value";
    }

    if (null === $z || "" === $z) {
        $z = "some other value";
    }

    code here!

}

ไม่สำคัญว่าคุณจะเติมข้อมูลnullหรือ""คุณจะได้รับผลลัพธ์เหมือนเดิม


0

ส่งผ่านอาร์เรย์ไปยังฟังก์ชันแทนที่จะใช้พารามิเตอร์แต่ละตัวและใช้ตัวดำเนินการรวมศูนย์ (PHP 7+)

ด้านล่างฉันผ่านอาร์เรย์ด้วย 2 รายการ ภายในฟังก์ชั่นนี้ฉันกำลังตรวจสอบว่ามีการตั้งค่าสำหรับ item1 หรือไม่ถ้าไม่ได้กำหนดค่าเริ่มต้น

$args = ['item2' => 'item2',
        'item3' => 'value3'];

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }

คุณสามารถใช้$args['item1'] = $args['item1']??'default value'; ใน PHP 7+ ถ้า $ args ['item1'] เป็นโมฆะdefault valueสตริงจะกำหนดให้กับ $ args ['item1']
Sadee
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.