Hàm PHP với các tham số tùy chọn


107

Tôi đã viết một hàm PHP có thể chấp nhận 10 tham số, nhưng chỉ cần 2 tham số. Đôi khi, tôi muốn xác định tham số thứ tám, nhưng tôi không muốn nhập các chuỗi trống cho từng tham số cho đến khi tôi đến tham số thứ tám.

Một ý tưởng mà tôi có là truyền một hàm trừu tượng hóa với một mảng các tham số để chuyển nó cùng với hàm thực.

Có cách nào tốt hơn để thiết lập hàm để tôi chỉ có thể truyền các tham số tôi muốn không?



Thật là lạ. Các hàm tích hợp sẵn trong php có thể có các tham số tùy chọn. Vậy tại sao chúng ta không thể xây dựng các hàm như vậy?
Rodrigo

2
Lưu ý rằng nhiều câu trả lời trong số này là NGOÀI RA ... PHP hiện hỗ trợ các hàm với danh sách đối số có độ dài thay đổi .
ashleedawg

Câu trả lời:


62

Làm cho hàm nhận một tham số: một mảng. Chuyển các tham số thực tế dưới dạng giá trị trong mảng.


Chỉnh sửa: liên kết trong bình luận của Pekka chỉ về tổng hợp nó.


1
Thật là lạ. Các hàm tích hợp sẵn trong php có thể có các tham số tùy chọn. Vậy tại sao chúng ta không thể xây dựng các hàm như vậy?
Rodrigo

1
@Rodrigo hoàn toàn có thể xác định được các hàm như thế. Tuy nhiên, chúng là tùy chọn vị trí, điều này khá tệ đối với bất kỳ thứ gì ngoài một tham số tùy chọn duy nhất.
Matt Ball

1
Được rồi, tôi đã thử với [], bây giờ tôi thấy cách thực hiện tại đây: stackoverflow.com/a/34869/1086511
Rodrigo

Có thể làm được nhiều hơn thế mà chỉ cần đề xuất "sử dụng một mảng" - hãy xem câu trả lời của Walf cho một câu hỏi tương tự và ví dụ chuyên sâu hơn trong cùng một chủ đề
DJDave

63

Những gì tôi đã làm trong trường hợp này là truyền một mảng, trong đó khóa là tên tham số và giá trị là giá trị.

$optional = array(
  "param" => $param1,
  "param2" => $param2
);

function func($required, $requiredTwo, $optional) {
  if(isset($optional["param2"])) {
    doWork();
  }
}

Đối với ví dụ của bạn, $ tùy chọn có cần phải được đặt toàn cục trong hàm không?
user481826

1
toàn cầu? Không..? Bạn tạo mảng đó trước khi gọi hàm và chuyển nó vào. Mã của tôi là một ví dụ về mô tả của Matt Balls về những gì nên làm.
Rabbott 21/10/10

Có hơn có thể được thực hiện mà chỉ là "sử dụng một mảng" gợi ý - hãy xem câu trả lời Walf để một câu hỏi tương tự và sâu hơn ví dụ trong cùng một thread
DJDave

45

Để đạt được những gì bạn muốn, hãy sử dụng một mảng Như Rabbot đã nói (mặc dù điều này có thể trở thành một vấn đề khó khăn trong việc lập tài liệu / bảo trì nếu sử dụng quá mức). Hoặc chỉ sử dụng args tùy chọn truyền thống.

//My function with tons of optional params
function my_func($req_a, $req_b, $opt_a = NULL, $opt_b = NULL, $opt_c = NULL)
{
  //Do stuff
}
my_func('Hi', 'World', null, null, 'Red');

Tuy nhiên, tôi thường thấy rằng khi tôi bắt đầu viết một hàm / phương thức với nhiều đối số như vậy - thường thì đó là một mùi mã và có thể được phân tích lại / trừu tượng hóa thành một thứ gì đó gọn gàng hơn nhiều.

//Specialization of my_func - assuming my_func itself cannot be refactored
function my_color_func($reg_a, $reg_b, $opt = 'Red')
{
  return my_func($reg_a, $reg_b, null, null, $opt);
}
my_color_func('Hi', 'World');
my_color_func('Hello', 'Universe', 'Green');

Vào năm 2010, các khái niệm như "mùi mã", "tái cấu trúc" hoặc "bảo trì mã" không phổ biến trong cộng đồng của chúng tôi. Bạn đã có một bước trước hầu hết chúng ta :)
Billal Begueradj

15

Trong PHP 5.6 trở lên, danh sách đối số có thể bao gồm ... mã thông báo để biểu thị rằng hàm chấp nhận một số lượng biến đối số. Các đối số sẽ được chuyển vào biến đã cho dưới dạng một mảng; ví dụ:

Ví dụ Sử dụng ... để truy cập các đối số biến

<?php
function sum(...$numbers) {
    $acc = 0;
    foreach ($numbers as $n) {
        $acc += $n;
    }
    return $acc;
}

echo sum(1, 2, 3, 4);
?>

Ví dụ trên sẽ xuất ra:

10

Đối số có độ dài thay đổi liệt kê Tài liệu PHP


Phản hồi này xứng đáng được nhiều điểm hơn. Không phù hợp với tình huống cụ thể của tôi nhưng thông tin tốt và đơn giản để hiểu. PHP 7.3 sẽ sớm ra mắt! 5,6 và 7 là EOL.
AdheneManx

12

Bạn chỉ có thể đặt giá trị mặc định thành null.

<?php
function functionName($value, $value2 = null) {
// do stuff
}

2
Câu trả lời tốt nhất, nhưng vui lòng thay thế nullbằng các bit không phải của loại ngày. ví dụ array()cho mảng
Mohamed hesham

Cảm ơn bạn ... Đây là những gì tôi đang tìm kiếm
Davide De Maestri

12

LƯU Ý: Đây là câu trả lời cũ, dành cho PHP 5.5 trở xuống. PHP 5.6+ hỗ trợ các đối số mặc định

Trong PHP 5.5 trở xuống, bạn có thể đạt được điều này bằng cách sử dụng một trong 2 phương pháp sau:

  • bằng cách sử dụng hàm func_num_args ()func_get_arg () ;
  • sử dụng đối số NULL;

Cách sử dụng

function method_1()
{
  $arg1 = (func_num_args() >= 1)? func_get_arg(0): "default_value_for_arg1";
  $arg2 = (func_num_args() >= 2)? func_get_arg(1): "default_value_for_arg2";
}

function method_2($arg1 = null, $arg2 = null)
{
  $arg1 = $arg1? $arg1: "default_value_for_arg1";
  $arg2 = $arg2? $arg2: "default_value_for_arg2";
}

Tôi thích phương pháp thứ hai hơn vì nó rõ ràng và dễ hiểu, nhưng đôi khi bạn có thể cần phương pháp đầu tiên.


1
Bạn cần dấu "=" kép ở đây nếu không tất cả các biểu thức sẽ trả về true. Ngoài ra, các biểu thức trong ví dụ thứ 2 sẽ luôn trả về true vì một biến luôn bằng với chính nó.
chuckieDub

điểm tốt, nhưng điều này thực sự hoạt động. Trong PHP, mã $x = null; if ($x) echo "true"; else echo "false";này sẽ in "false", ngay cả khi $ x var có giá trị ("null" trong mã này). Ngoài ra, trong cả hai phương pháp, chúng tôi đang sử dụng toán tử bậc ba, vì vậy, đúng là chỉ sử dụng một "=". Nếu bạn kiểm tra với method(); method(1); method(1, 2);, thì lệnh gọi đầu tiên sẽ liên kết arg1 và arg2 với các giá trị mặc định, lệnh gọi thứ hai sẽ liên kết đối số thứ hai với giá trị mặc định và "1" cho đối số đầu tiên. Cuộc gọi cuối cùng sẽ không liên kết các giá trị mặc định.
Daniel Loureiro

1
chức năng method_2 ($ arg1 = "default_value_fot_arg1", $ arg2 = "default_value_fot_arg2") {để thỏa thuận php với các công cụ tham số và cũng có thể bạn có thể vượt qua null như tham số (tại sao mọi người sử dụng null Tôi không biết)
nerkn

1
@nerkn, bạn nói đúng, PHP hiện hỗ trợ các đối số mặc định. Lol, tôi nhớ khi chúng ta cần phải thực hiện rất nhiều cách giải quyết để đạt được những điều đơn giản. Thời điểm tốt: P Tuy nhiên, bạn vẫn có thể thấy những cách tiếp cận đó trong các mã cũ (trước 5.5).
Daniel Loureiro

4

Tôi nghĩ, bạn cũng có thể sử dụng các đối tượng làm params-transportes.

$myParam = new stdClass();
$myParam->optParam2 = 'something';
$myParam->optParam8 = 3;
theFunction($myParam);

function theFunction($fparam){      
  return "I got ".$fparam->optParam8." of ".$fparam->optParam2." received!";
}

Tất nhiên, bạn phải đặt giá trị mặc định cho "optParam8" và "optParam2" trong hàm này, trong trường hợp khác, bạn sẽ nhận được "Thông báo: Thuộc tính không xác định: stdClass :: $ optParam2"

Nếu sử dụng mảng làm tham số hàm, tôi thích cách này để đặt giá trị mặc định:

function theFunction($fparam){
   $default = array(
      'opt1' => 'nothing',
      'opt2' => 1
   );
   if(is_array($fparam)){
      $fparam = array_merge($default, $fparam);
   }else{
      $fparam = $default;
   }
   //now, the default values are overwritten by these passed by $fparam
   return "I received ".$fparam['opt1']." and ".$fparam['opt2']."!";
}

2

Nếu chỉ cần hai giá trị để tạo đối tượng với trạng thái hợp lệ, bạn có thể chỉ cần xóa tất cả các đối số tùy chọn khác và cung cấp bộ định tuyến cho chúng (trừ khi bạn không muốn chúng thay đổi trong thời gian chạy). Sau đó, chỉ cần khởi tạo đối tượng với hai đối số được yêu cầu và thiết lập các đối số khác khi cần thông qua trình thiết lập.

đọc thêm


2

Tôi biết đây là một bài viết cũ, nhưng tôi đã gặp vấn đề như OP và đây là những gì tôi đã nghĩ ra.

Ví dụ về mảng bạn có thể vượt qua. Bạn có thể đặt hàng lại nếu một đơn hàng cụ thể được yêu cầu, nhưng đối với câu hỏi này, điều này sẽ thực hiện những gì được yêu cầu.

$argument_set = array (8 => 'lots', 5 => 'of', 1 => 'data', 2 => 'here');

Điều này có thể quản lý, dễ đọc và các điểm trích xuất dữ liệu có thể được thêm và xóa ngay lập tức ở bất kỳ đâu trong quá trình mã hóa mà vẫn tránh phải viết lại nhiều. Tôi đã sử dụng các khóa số nguyên để kiểm đếm với câu hỏi gốc OP nhưng các khóa chuỗi có thể được sử dụng dễ dàng như vậy. Trong thực tế để dễ đọc, tôi sẽ khuyên nó.

Gắn nó vào một tệp bên ngoài để dễ dàng

function unknown_number_arguments($argument_set) {

    foreach ($argument_set as $key => $value) {

        # create a switch with all the cases you need. as you loop the array 
        # keys only your submitted $keys values will be found with the switch. 
        switch ($key) {
            case 1:
                # do stuff with $value
                break;
            case 2:
                # do stuff with $value;
                break;
            case 3:
                # key 3 omitted, this wont execute 
                break;
            case 5:
                # do stuff with $value;
                break;
            case 8:
                # do stuff with $value;
                break;
            default:
                # no match from the array, do error logging?
                break;
        }
    }
return;
}

đặt điều này ở đầu nếu tệp.

$argument_set = array(); 

Chỉ cần sử dụng chúng để gán cho phần dữ liệu tiếp theo, sử dụng đánh số / đặt tên tùy theo nơi dữ liệu đến.

$argument_set[1][] = $some_variable; 

Và cuối cùng vượt qua mảng

unknown_number_arguments($argument_set);

1
function yourFunction($var1, $var2, $optional = Null){
   ... code
}

Bạn có thể tạo một hàm thông thường và sau đó thêm các biến tùy chọn của mình bằng cách đặt cho chúng một giá trị Null mặc định.

Null vẫn là một giá trị, nếu bạn không gọi hàm với giá trị cho biến đó, nó sẽ không rỗng nên không có lỗi.


2
Bạn có thể giải thích thêm không? Mã nhất định được cú pháp không hợp lệ, như tên biến không thể bắt đầu với một số
Nico Haase

0

Nếu bạn thường chỉ chuyển giá trị thứ 8, bạn có thể sắp xếp lại thứ tự các tham số của mình để nó là giá trị đầu tiên. Bạn chỉ cần chỉ định các tham số cho đến khi bạn muốn thiết lập tham số cuối cùng.

Nếu bạn đang sử dụng các giá trị khác nhau, bạn có 2 tùy chọn.

Một là tạo một tập hợp các hàm trình bao bọc lấy các tham số khác nhau và đặt giá trị mặc định cho các hàm khác. Điều này rất hữu ích nếu bạn chỉ sử dụng một số kết hợp, nhưng có thể trở nên rất lộn xộn nhanh chóng.

Tùy chọn khác là truyền một mảng trong đó các khóa là tên của các tham số. Sau đó, bạn có thể chỉ cần kiểm tra xem có giá trị nào trong mảng bằng khóa hay không và nếu không thì sử dụng giá trị mặc định. Nhưng một lần nữa, điều này có thể trở nên lộn xộn và thêm nhiều mã bổ sung nếu bạn có nhiều tham số.


0

PHP cho phép các đối số mặc định ( liên kết ). Trong trường hợp của bạn, bạn có thể xác định tất cả các tham số từ 3 đến 8 là NULL hoặc dưới dạng chuỗi trống "" tùy thuộc vào mã hàm của bạn. Bằng cách này, bạn có thể gọi hàm chỉ bằng cách sử dụng hai tham số đầu tiên.

Ví dụ:

<?php
  function yourFunction($arg1, $arg2, $arg3=NULL, $arg4=NULL, $arg5=NULL, $arg6=NULL, $arg7=NULL, $arg8=NULL){
echo $arg1;
echo $arg2;
if(isset($arg3)){echo $arg3;}
# other similar statements for $arg4, ...., $arg5
if(isset($arg8)){echo $arg8;}
}

Ý tưởng thú vị ... tuy nhiên đề xuất của bạn không giải quyết được vấn đề. Trên thực tế, nếu bạn thêm thông tin về đối số nào đang được lặp lại (ví dụ: bằng cách sử dụng echo " this is arg3: " . $arg3;, v.v., bạn sẽ thấy lệnh gọi ví dụ yourFunction(3, 2, $arg8=5);sẽ in ra 32 this is arg3: 5. Vấn đề là vị trí tham số vẫn quan trọng khi truyền tham số tùy chọn trong PHP ... không đủ để ánh xạ các giá trị thông số với tên thông số.
mastropi

0

Chỉ cần đặt Null để bỏ qua các tham số mà bạn không muốn sử dụng và sau đó đặt tham số cần thiết theo vị trí.

 function myFunc($p1,$p2,$p3=Null,$p4=Null,$p5=Null,$p6=Null,$p7=Null,$p8=Null){
    for ($i=1; $i<9; $i++){
        $varName = "p$i";
        if (isset($$varName)){
            echo $varName." = ".$$varName."<br>\n";
        }
    }
}   

myFunc( "1", "2", Null, Null, Null, Null, Null, "eight" );

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.