programing

함수 호출에서 선택적 인수를 어떻게 건너 뛰나요?

nasanasas 2020. 9. 19. 11:23
반응형

함수 호출에서 선택적 인수를 어떻게 건너 뛰나요?


좋아, PHP에서 인수를 건너 뛰는 방법을 완전히 잊었습니다.

내가 가지고 있다고 가정 해 봅시다.

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

중간 매개 변수가 기본값 (예 : '50')을 사용하도록이 함수를 어떻게 호출합니까?

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

위의 내용이 맞습니까? 이 작업을 수행 할 수없는 것 같습니다.


귀하의 게시물이 정확합니다.

안타깝게도 매개 변수 목록 맨 끝에 선택적 매개 변수를 사용해야하는 경우 마지막 매개 변수까지 모든 것을 지정해야합니다. 일반적으로 당신이 앤 매치를 혼합하려는 경우, 당신은 그들에게의 디폴트 값을 제공 ''또는 null, 그들은 그 기본값 경우 함수 내에서 사용하지 않습니다.


false또는 과 같은 기본값을 지정하는 것 외에 다른 인수를 "건너 뛰는"방법은 없습니다 null.

PHP에는 이와 관련하여 구문상의 설탕이 부족하기 때문에 다음과 같은 내용이 자주 표시됩니다.

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

주석에서 웅변 적으로 말했듯이 배열을 사용하여 명명 된 인수를 에뮬레이트합니다.

이는 궁극적 인 유연성을 제공하지만 경우에 따라 필요하지 않을 수 있습니다. 최소한 대부분의 시간에 예상하지 못했던 것으로 생각되는 모든 항목을 인수 목록의 끝으로 이동할 수 있습니다.


아니요, 이런 식으로 인수를 건너 뛸 수 없습니다. 매개 변수 목록의 끝에있는 경우 에만 인수 전달을 생략 할 수 있습니다 .

이에 대한 공식적인 제안이있었습니다 : https://wiki.php.net/rfc/skipparams , 거절당했습니다. 제안 페이지는이 주제에 대한 다른 SO 질문으로 연결됩니다.


선택적 인수를 건너 뛸 수있는 것과 관련하여 변경된 사항은 없지만 올바른 구문과 건너 뛰려는 인수에 대해 NULL을 지정할 수 있도록하려면 다음과 같이하십시오.

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

이렇게 getData('some name',NULL,'23');호출 할 수 있습니다. 앞으로 함수를 호출하는 사람은 매번 기본값이나 선언 된 상수를 기억할 필요가 없습니다.


간단한 대답은 아니오 입니다. 그러나 인수를 재정렬 할 때이를 건너 뛰는 이유는 무엇입니까?

귀하는 " 기본 함수 인수의 잘못된 사용 "이며 예상대로 작동하지 않습니다.

PHP 문서의 추가 정보 :

기본 인수를 사용할 때 모든 기본값은 기본값이 아닌 인수의 오른쪽에 있어야합니다. 그렇지 않으면 예상대로 작동하지 않습니다.

다음을 고려하세요:

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

출력은 다음과 같습니다.

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

기본 함수 인수의 올바른 사용법은 다음과 같아야합니다.

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

출력은 다음과 같습니다.

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

기본값이 아닌 다음 오른쪽에 기본값을두면 해당 변수가 정의 / 주어지지 않은 경우 항상 해당 변수의 기본값을 되돌릴 수 있습니다. 참조 용 링크 와 해당 예제의 출처가 여기에 있습니다.

편집 : null다른 사람들이 제안한대로 설정하면 작동 할 수 있으며 또 다른 대안이지만 원하는 것에 적합하지 않을 수 있습니다. 정의되지 않은 경우 항상 기본값을 null로 설정합니다.


건너 뛴 매개 변수에 대해서는 기본 매개 변수를 사용하여 안전을 유지하십시오.

(기본 매개 변수가 ''또는 이와 유사하거나 그 반대 인 경우 null로 설정하면 문제가 발생합니다 ...)


위에서 언급했듯이 매개 변수를 건너 뛸 수 없습니다. 나는 주석을 달기에는 너무 큰 부록을 제공하기 위해이 답변을 작성했습니다.

@Frank Nocke 는 기본 매개 변수를 사용하여 함수를 호출하도록 제안 합니다.

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

당신은 사용해야합니다

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

처음 두 개의 ( $b$c) 매개 변수 를 생략하는 것과 기능적으로 동일 합니다.

어떤 것이 기본값인지 명확하지 않습니다 (기본값 0을 제공하기 위해 입력 했습니까, 아니면 중요합니까?).

또한 함수 (또는 메서드) 작성자가 기본값을 변경할 수있는 경우 기본값 문제가 외부 (또는 내장) 함수와 연결될 위험이 있습니다. 따라서 프로그램에서 호출을 변경하지 않으면 의도하지 않게 동작을 변경할 수 있습니다.

몇 가지 해결 방법은 다음과 같이 DEFAULT_A_B"함수 A의 B 매개 변수의 기본값"및 "생략"매개 변수와 같은 전역 상수를 정의 하는 것입니다.

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

클래스의 경우 클래스 상수를 정의하면 더 쉽고 우아합니다. 예를 들어 전역 범위의 일부이기 때문입니다.

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.

이 기본 상수는 코드 전체에서 정확히 한 번 정의되므로 (메서드 선언에도 값이 없음) 예기치 않은 변경이 발생하는 경우 항상 올바른 기본값으로 함수 / 메서드를 제공합니다.

물론이 솔루션의 명확성은 독자에게 아무 말도하지 않는 원시 기본값 (예 NULL: 0등)을 제공하는 것보다 낫습니다 .

(같은 전화 $var = a(,,'ddd');가 최선의 선택이 될 것이라는 데 동의합니다 )


인수를 건너 뛸 수는 없지만 배열 매개 변수를 사용할 수 있으며 매개 변수 배열 인 1 개의 매개 변수 만 정의하면됩니다.

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

또한 필요한만큼의 매개 변수를 추가 할 수 있으며 정의 할 필요가 없습니다. 함수를 호출 할 때 다음과 같이 매개 변수를 입력합니다.

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

다른 모든 사람들이 이미 말했듯이 함수에 코드 줄을 추가하지 않고는 PHP에서 원하는 것이 가능하지 않을 것이라고 말했습니다.

그러나이 코드 조각을 함수 맨 위에 배치하여 기능을 얻을 수 있습니다.

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

따라서 기본적 debug_backtrace()으로이 코드가 배치 된 함수 이름을 얻은 다음 새 ReflectionFunction개체 를 만들고 모든 함수 인수를 반복합니다.

루프에서 함수 empty()인수가 "선택 사항" 인지 확인하기 만하면됩니다 (기본값이 있음을 의미). 그렇다면 단순히 기본값을 인수에 할당합니다.

Demo


제한을 null로 설정

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

그 함수를 호출

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

제한을 설정하려면 인수로 전달할 수 있습니다.

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

앞서 언급 했듯이 아무것도 변경되지 않았습니다. 그러나 너무 많은 매개 변수 (특히 선택적 매개 변수)는 코드 냄새의 강력한 지표입니다.

아마도 당신의 기능이 너무 많은 일을하고있을 것입니다 :

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

일부 매개 변수는 논리적으로 그룹화 할 수 있습니다.

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

마지막 수단으로 언제든지 임시 매개 변수 객체를 도입 할 수 있습니다 .

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

(이는 덜 형식적인 매개 변수 배열 기법 의 미화 버전 일뿐입니다 )

Sometimes, the very reason for making a parameter optional is wrong. In this example, is $page really meant to be optional? Does saving a couple of characters really make a difference?

// 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 */);

This snippet:


    function getData($name, $options) {
       $default = array(
            'limit' => 50,
            'page' => 2,
        );
        $args = array_merge($default, $options);
        print_r($args);
    }

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

Answer is :


     Array
    (
        [limit] => 50
        [page] => 2
    )
    Array
    (
        [limit] => 2
        [page] => 2
    )
    Array
    (
        [limit] => 10
        [page] => 10
    )


This is what I would do:

<?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 */

?>

Hope this will help someone


This is kind of an old question with a number of technically competent answers, but it cries out for one of the modern design patterns in PHP: Object-Oriented Programming. Instead of injecting a collection of primitive scalar data types, consider using an "injected-object" that contains all of the data needed by the function. http://php.net/manual/en/language.types.intro.php

The injected-object may have property validation routines, etc. If the instantiation and injection of data into the injected-object is unable to pass all of the validation, the code can throw an exception immediately and the application can avoid the awkward process of dealing with potentially incomplete data.

We can type-hint the injected-object to catch mistakes before deployment. Some of the ideas are summarized in this article from a few years ago.

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


Try This.

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

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

You can not skip middle parameter in your function call. But, you can work around with this:

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

Function:

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

As @IbrahimLawal pointed out. It's best practice to just set them to null values. Just check if the value passed is null in which you use your defined defaults.

<?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;
    ...
}
?>

Hope this helps.


getData('some name');

just do not pass them and the default value will be accepted

참고URL : https://stackoverflow.com/questions/1066625/how-would-i-skip-optional-arguments-in-a-function-call

반응형