Làm cách nào để bỏ qua các đối số tùy chọn trong một lệnh gọi hàm?


94

OK, tôi hoàn toàn quên cách bỏ qua các đối số trong PHP.

Hãy nói rằng tôi có:

function getData($name, $limit = '50', $page = '1') {
    ...
}

Làm cách nào để gọi hàm này để tham số giữa nhận giá trị mặc định (ví dụ: '50')?

getData('some name', '', '23');

Điều trên có đúng không? Tôi dường như không thể làm cho việc này hoạt động.


1
@Chuck cho chính xác bạn đang tìm kiếm điều gì? Giống như một giải pháp thay thế hoặc một lớp để thực hiện điều này hoặc ...?
Rizier123

@ Rizier123 Tôi đang hỏi xem phiên bản PHP hiện tại có hỗ trợ bỏ qua các đối số hay không (giống như các ngôn ngữ khác). Các câu trả lời hiện tại có thể đã lỗi thời. Từ mô tả tiền thưởng: "Các câu trả lời hiện tại đã được 5 năm. Phiên bản PHP hiện tại có thay đổi mọi thứ không?"
Chuck Le Butt

1
@Chuck Sau đó, câu trả lời có thể sẽ là: không có gì thay đổi; nếu không có giải pháp / mã, bạn sẽ không nhận được chức năng của mình.
Rizier123

Tất cả các câu trả lời ở đây dường như giả sử bạn có quyền kiểm soát đối với chức năng đang được gọi. Nếu hàm đó là một phần của thư viện hoặc khuôn khổ, bạn không có tùy chọn nào khác ngoài việc chỉ định điều gì đó cho đối số 2 nếu bạn cần đối số 3. Tùy chọn duy nhất là tìm kiếm trong nguồn của hàm và sao chép giá trị mặc định.
Snapey

Không thể bỏ qua nó, nhưng bạn có thể chuyển đối số mặc định bằng cách sử dụng ReflectionFunction. Tôi đã đăng câu trả lời đó trong một câu hỏi tương tự.
David

Câu trả lời:


55

Bài viết của bạn là chính xác.

Thật không may, nếu bạn cần sử dụng một tham số tùy chọn ở cuối danh sách tham số, bạn phải chỉ định mọi thứ cho đến tham số cuối cùng đó. Nói chung, nếu bạn muốn trộn và kết hợp, bạn cung cấp cho chúng các giá trị mặc định là ''hoặc nullvà không sử dụng chúng bên trong hàm nếu chúng là giá trị mặc định đó.


1
bạn có thể cung cấp một ví dụ?
tôi là tôi

2
@iamme làm $limit = is_numeric($limit) ? $limit : '50';vào đầu getData chức năng
Kamafeather

40

Không có cách nào để "bỏ qua" một đối số ngoài việc chỉ định một giá trị mặc định như falsehoặcnull .

Vì PHP thiếu một số cú pháp khi nói đến điều này, bạn thường sẽ thấy một số thứ như sau:

checkbox_field(array(
    'name' => 'some name',
    ....
));

Như đã nói một cách hùng hồn trong các nhận xét, đang sử dụng các mảng để mô phỏng các đối số được đặt tên.

Điều này mang lại sự linh hoạt tối ưu nhưng có thể không cần thiết trong một số trường hợp. Ít nhất thì bạn có thể di chuyển bất cứ điều gì bạn cho là không mong đợi hầu hết thời gian đến cuối danh sách đối số.


2
Tôi sẽ xác định 'một cái gì đó như thế này' là 'sử dụng các mảng để mô phỏng các đối số được đặt tên', FWIW. :)
hỗn loạn

3
Mặc dù linh hoạt hơn nhưng bạn phải nhớ các tham số bạn nên / có thể đặt (vì chúng không có trong chữ ký). Vì vậy, cuối cùng nó có thể không hữu ích như nó có vẻ nhưng tất nhiên điều này phụ thuộc vào ngữ cảnh.
Felix Kling

Vì vậy, những gì sẽ là thực hành tốt nhất cho một kịch bản như vậy?
Adam Grant

39

Không, không thể bỏ qua các lập luận theo cách này. Bạn có thể bỏ qua qua các đối số duy nhất nếu họ đang ở cuối danh sách tham số.

Có một đề xuất chính thức cho việc này: https://wiki.php.net/rfc/skipparams , nhưng đã bị từ chối. Trang đề xuất liên kết đến các câu hỏi SO khác về chủ đề này.


Sau đó, làm thế nào để các hàm PHP có tùy chọn nhiều hơn / ít tham số hơn?
tôi là tôi

2
PHP có hỗ trợ các giá trị tham số mặc định. Nhưng những thông số đó phải ở cuối danh sách.
Cristik

1
Bạn có thể tìm thấy các ví dụ trong tài liệu PHP
Cristik.

2
Giật gân. Khiến tôi phát điên lên. Nếu bạn không thích một tính năng mà người khác yêu cầu, chỉ cần không sử dụng nó. Internet đôi khi là tồi tệ nhất.
Lee Saxon

@LeeSaxon vấn đề là khả năng đọc và tính di động. 1) Nếu ai đó quyết định bỏ qua các tham số và ai đó mã gỡ lỗi bỏ lỡ thực tế này, thì sự nhầm lẫn lớn sẽ xảy ra. 2) mã mới không thể hoạt động trên các phiên bản cũ hơn nếu không có quá trình lớn và khả năng mắc lỗi sẽ rất cao.
Mark Walsh

6

Không có gì thay đổi liên quan đến việc có thể bỏ qua các đối số tùy chọn, tuy nhiên để có cú pháp chính xác và có thể chỉ định NULL cho các đối số mà tôi muốn bỏ qua, đây là cách tôi thực hiện:

define('DEFAULT_DATA_LIMIT', '50');
define('DEFAULT_DATA_PAGE', '1');

/**
 * getData
 * get a page of data 
 *
 * Parameters:
 *     name - (required) the name of data to obtain
 *     limit - (optional) send NULL to get the default limit: 50
 *     page - (optional) send NULL to get the default page: 1
 * Returns:
 *     a page of data as an array
 */

function getData($name, $limit = NULL, $page = NULL) {
    $limit = ($limit===NULL) ? DEFAULT_DATA_LIMIT : $limit;
    $page = ($page===NULL) ? DEFAULT_DATA_PAGE : $page;
    ...
}

Điều này có thể được gọi như vậy: getData('some name',NULL,'23');và bất kỳ ai gọi hàm trong tương lai đều không cần nhớ các giá trị mặc định mỗi lần hoặc hằng được khai báo cho chúng.


1
Bạn có thể muốn so sánh chặt chẽ ($ giới hạn === null)
roelleor

4

Câu trả lời đơn giản là Không . Nhưng tại sao lại bỏ qua khi sắp xếp lại các đối số đạt được điều này?

Của bạn là " Sử dụng không chính xác các đối số hàm mặc định " và sẽ không hoạt động như bạn mong đợi.

Một lưu ý phụ từ tài liệu PHP:

Khi sử dụng các đối số mặc định, mọi giá trị mặc định phải ở bên phải của mọi đối số không mặc định; nếu không, mọi thứ sẽ không diễn ra như mong đợi.

Hãy xem xét những điều sau:

function getData($name, $limit = '50', $page = '1') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '', '23');   // won't work as expected

Đầu ra sẽ là:

"Select * FROM books WHERE name = some name AND page = 23 limit"

Cách sử dụng đúng các đối số của hàm mặc định sẽ như thế này:

function getData($name, $page = '1', $limit = '50') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '23');  // works as expected

Đầu ra sẽ là:

"Select * FROM books WHERE name = some name AND page = 23 limit 50"

Đặt giá trị mặc định ở bên phải của bạn sau các giá trị không mặc định đảm bảo rằng nó sẽ luôn chạy lại giá trị mặc định cho biến đó nếu biến đó không được xác định / cho Đây là liên kết để tham khảo và các ví dụ đó đến từ đâu.

Chỉnh sửa: Đặt nó thành nullnhư những người khác đang đề xuất có thể hoạt động và là một thay thế khác, nhưng có thể không phù hợp với những gì bạn muốn. Nó sẽ luôn đặt mặc định thành null nếu nó không được xác định.


Đây là câu trả lời tốt nhất vì nó cung cấp các giải thích cú pháp được minh họa rõ ràng! Cảm ơn bạn!
Christian

2

Đối với bất kỳ tham số nào bị bỏ qua (bạn phải) đi với tham số mặc định, để ở bên an toàn.

(Giải quyết null trong đó tham số mặc định là '' hoặc tương tự hoặc ngược lại sẽ khiến bạn gặp rắc rối ...)


2

Như đã đề cập ở trên, bạn sẽ không thể bỏ qua các tham số. Tôi đã viết câu trả lời này để cung cấp một số phụ lục, quá lớn để đưa vào một bình luận.

@Frank Nocke đề xuất gọi hàm với các tham số mặc định của nó, vì vậy, ví dụ: có

function a($b=0, $c=NULL, $d=''){ //...

bạn nên sử dụng

$var = a(0, NULL, 'ddd'); 

về mặt chức năng sẽ giống như bỏ qua hai ( $b$c) tham số đầu tiên .

Không rõ cái nào là 0giá trị mặc định (được nhập để cung cấp giá trị mặc định, hay nó quan trọng?).

Cũng có một nguy cơ là vấn đề giá trị mặc định được kết nối với chức năng bên ngoài (hoặc tích hợp sẵn), khi các giá trị mặc định có thể bị thay đổi bởi tác giả của hàm (hoặc phương pháp). Vì vậy, nếu bạn không thay đổi cuộc gọi của mình trong chương trình, bạn có thể vô tình thay đổi hành vi của nó.

Một số cách giải quyết có thể là xác định một số hằng số toàn cục, chẳng hạn như DEFAULT_A_Bsẽ là "giá trị mặc định của tham số B của hàm A" và "bỏ qua" tham số theo cách này:

$var = a(DEFAULT_A_B, DEFAULT_A_C, 'ddd');

Đối với các lớp sẽ dễ dàng và thanh lịch hơn nếu bạn định nghĩa các hằng số của lớp, vì chúng là một phần của phạm vi toàn cục, ví dụ.

class MyObjectClass {
  const DEFAULT_A_B = 0;

  function a($b = self::DEFAULT_A_B){
    // method body
  }
} 
$obj = new MyObjectClass();
$var = $obj->a(MyObjectClass::DEFAULT_A_B); //etc.

Lưu ý rằng hằng số mặc định này được xác định chính xác một lần trong toàn bộ mã (không có giá trị ngay cả trong khai báo phương thức), vì vậy trong trường hợp có một số thay đổi không mong muốn, bạn sẽ luôn cung cấp hàm / phương thức với giá trị mặc định chính xác.

Sự rõ ràng của giải pháp này tất nhiên là tốt hơn so với việc cung cấp các giá trị mặc định thô (như NULL, 0v.v.) không nói gì đến người đọc.

(Tôi đồng ý rằng gọi như thế $var = a(,,'ddd');sẽ là lựa chọn tốt nhất)


2

Bạn không thể bỏ qua các đối số nhưng bạn có thể sử dụng các tham số mảng và bạn chỉ cần xác định 1 tham số, đó là một mảng tham số.

function myfunction($array_param)
{
    echo $array_param['name'];
    echo $array_param['age'];
    .............
}

Và bạn có thể thêm bao nhiêu tham số bạn cần, bạn không cần xác định chúng. Khi bạn gọi hàm, bạn đặt các tham số của mình như sau:

myfunction(array("name" => "Bob","age" => "18", .........));

0

Như mọi người đã nói, điều bạn muốn sẽ không thể thực hiện được trong PHP nếu không thêm bất kỳ dòng mã nào trong hàm.

Nhưng bạn có thể đặt đoạn mã này ở đầu một hàm để có được chức năng của mình:

foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
    if(empty(${$param->getName()}) && $param->isOptional())
        ${$param->getName()} = $param->getDefaultValue();
}

Vì vậy, về cơ bản với debug_backtrace()tôi lấy tên hàm mà mã này được đặt, sau đó tạo một ReflectionFunctionđối tượng mới và lặp qua tất cả các đối số của hàm.

Trong vòng lặp, tôi chỉ cần kiểm tra xem đối số của hàm có phải là empty()VÀ đối số là "tùy chọn" (có nghĩa là nó có giá trị mặc định) hay không. Nếu có, tôi chỉ cần gán giá trị mặc định cho đối số.

Demo


0

Đặt giới hạn thành null

function getData($name, $limit = null, $page = '1') {
    ...
}

và gọi đến chức năng đó

getData('some name', null, '23');

nếu bạn muốn đặt giới hạn, bạn có thể chuyển làm đối số

getData('some name', 50, '23');

0

Như đã khuyên trước đó , không có gì thay đổi. Tuy nhiên, hãy cẩn thận, quá nhiều thông số (đặc biệt là những thông số tùy chọn) là một chỉ báo mạnh về mùi mã.

Có lẽ chức năng của bạn đang hoạt động quá nhiều:

// first build context
$dataFetcher->setPage(1);
// $dataFetcher->setPageSize(50); // not used here
// then do the job
$dataFetcher->getData('some name');

Một số tham số có thể được nhóm một cách hợp lý:

$pagination = new Pagination(1 /*, 50*/);
getData('some name', $pagination);
// Java coders will probably be familiar with this form:
getData('some name', new Pagination(1));

Cuối cùng, bạn luôn có thể giới thiệu một đối tượng tham số đặc biệt :

$param = new GetDataParameter();
$param->setPage(1);
// $param->setPageSize(50); // not used here
getData($param);

(chỉ là một phiên bản tôn vinh của kỹ thuật mảng tham số ít chính thức hơn )

Đôi khi, chính lý do để tạo một tham số tùy chọn là sai. Trong ví dụ này, có $pagethực sự là tùy chọn không? Việc lưu một vài ký tự có thực sự tạo ra sự khác biệt?

// dubious
// it is not obvious at first sight that a parameterless call to "getData()"
// returns only one page of data
function getData($page = 1);

// this makes more sense
function log($message, $timestamp = null /* current time by default */);

0

Đoạn mã này:

    function getData ($ name, $ options) {
       $ default = array (
            'giới hạn' => 50,
            'trang' => 2,
        );
        $ args = array_merge ($ default, $ options);
        print_r ($ args);
    }

    getData ('foo', array ());
    getData ('foo', array ('limit' => 2));
    getData ('foo', array ('limit' => 10, 'page' => 10));

Câu trả lời là :

     Mảng
    (
        [giới hạn] => 50
        [trang] => 2
    )
    Mảng
    (
        [giới hạn] => 2
        [trang] => 2
    )
    Mảng
    (
        [giới hạn] => 10
        [trang] => 10
    )


2
Đẹp. Nhưng một chút giải thích sẽ hữu ích.
showdev

Câu trả lời hay, nhưng nếu bạn muốn bỏ qua tham số tùy chọn, hãy làm theo cách này: function getData ($ name, $ args = array ()) {$ defaults = array ('limit': => 50, 'page' => 2) ; $ args = array_merge ($ defaults, $ args); } Bây giờ có thể gọi hàm này chỉ với tham số đầu tiên như sau: getData ('foo');
EchoSin

0

Đây là những gì tôi sẽ làm:

<?php

    function getData($name, $limit = '', $page = '1') {
            $limit = (EMPTY($limit)) ? 50 : $limit;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

     echo getData('table');

    /* output name=table&limit=50&page=1 */

     echo getData('table',20);

    /* name=table&limit=20&page=1 */

    echo getData('table','',5);

    /* output name=table&limit=50&page=5 */

    function getData2($name, $limit = NULL, $page = '1') {
            $limit = (ISSET($limit)) ? $limit : 50;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

    echo getData2('table');

    // /* output name=table&limit=50&page=1 */

    echo getData2('table',20);

    /* output name=table&limit=20&page=1 */

    echo getData2('table',NULL,3);

    /* output name=table&limit=50&page=3 */

?>

Hy vọng điều này sẽ giúp ai đó


0

Đây là một dạng câu hỏi cũ với một số câu trả lời có thẩm quyền về mặt kỹ thuật, nhưng nó lại mắc phải một trong những mẫu thiết kế hiện đại trong PHP: Lập trình hướng đối tượng. Thay vì đưa vào một bộ sưu tập các kiểu dữ liệu vô hướng nguyên thủy, hãy xem xét sử dụng một "đối tượng được chèn" có chứa tất cả dữ liệu mà hàm cần. http://php.net/manual/en/language.types.intro.php

Đối tượng được đưa vào có thể có các quy trình xác thực thuộc tính, v.v. Nếu việc khởi tạo và đưa dữ liệu vào đối tượng được chèn không thể vượt qua tất cả các xác thực, mã có thể đưa ra một ngoại lệ ngay lập tức và ứng dụng có thể tránh được quá trình xử lý khó xử với dữ liệu có khả năng không đầy đủ.

Chúng ta có thể gõ-gợi ý đối tượng được tiêm vào để bắt lỗi trước khi triển khai. Một số ý tưởng được tóm tắt trong bài báo này từ một vài năm trước.

https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html


0

Tôi phải tạo Nhà máy với các tham số tùy chọn, cách giải quyết của tôi là sử dụng toán tử liên kết null:

public static function make(
    string $first_name = null,
    string $last_name = null,
    string $email = null,
    string $subject = null,
    string $message = null
) {
    $first_name = $first_name ?? 'First';
    $last_name  = $last_name ?? 'Last';
    $email      = $email ?? 'foo@bar.com';
    $subject    = $subject ?? 'Some subject';
    $message    = $message ?? 'Some message';
}

Sử dụng:

$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');

Không phải là thứ đẹp nhất, nhưng có thể là một mẫu tốt để sử dụng trong Factories cho các bài kiểm tra.


-1

Thử cái này.

function getData($name, $limit = NULL, $page = '1') {
               if (!$limit){
                 $limit = 50;
               }
}

getData('some name', '', '23');

-2

Bạn không thể bỏ qua tham số giữa trong lệnh gọi hàm của mình. Tuy nhiên, bạn có thể giải quyết vấn đề này:

function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.

Chức năng:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}

Tôi không chắc tại sao bạn lại bỏ phiếu, ngoài việc $ c cũng cần một giá trị mặc định (bạn không thể có bất kỳ đối số bắt buộc nào sau đối số tùy chọn).
Frank Forte

-2

Như @IbrahimLawal đã chỉ ra. Cách tốt nhất là chỉ đặt chúng thành nullcác giá trị. Chỉ cần kiểm tra xem giá trị được truyền có phải là giá trị nullmà bạn sử dụng mặc định đã xác định hay không.

<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);

function getData($name, $limit = null, $page = null) {
    $limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
    $page = is_null($page) ? DEFAULT_PAGE : $page;
    ...
}
?>

Hi vọng điêu nay co ich.


Bạn chỉ cần sao chép phản hồi. Thay vì bạn có thể đã ủng hộ hoặc bình luận về nó.
Ibrahim Lawal

-6
getData('some name');

chỉ cần không vượt qua chúng và giá trị mặc định sẽ được chấp nhận

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.