Як пропустити необов’язкові аргументи у виклику функції?


94

Добре, я зовсім забув, як пропустити аргументи в PHP.

Скажімо, у мене є:

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

Як би я викликав цю функцію, щоб середній параметр приймав значення за замовчуванням (тобто "50")?

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

Чи правильно було б сказане вище? Здається, я не можу змусити це спрацювати.


1
@Chuck для чого саме ти шукаєш? Як обхідний шлях або клас для реалізації цього чи ...?
Різьєр 123

@ Rizier123 Я прошу перевірити, чи підтримує поточна версія PHP пропуск аргументів (як це роблять інші мови). Поточні відповіді можуть бути застарілими. З опису нагороди: "Поточним відповідям п'ять років. Чи змінює поточна версія PHP щось?"
Чак Ле Батт

1
@Chuck Тоді відповідь, мабуть, буде така: що нічого не змінилося; без обхідного рішення / коду ви не отримаєте свою функціональність.
Різьєр 123,

Всі відповіді тут, здається, передбачають, що ви маєте контроль над функцією, що викликається. Якщо ця функція є частиною бібліотеки або фреймворку, у вас немає можливості, окрім як вказати щось для аргументу 2, якщо вам потрібен аргумент 3. Єдиним варіантом є пошук функції у джерелі та реплікація значення за замовчуванням.
Снейпі

Це неможливо пропустити, але ви можете передати аргумент за замовчуванням, використовуючи ReflectionFunction. Я розмістив цю відповідь у подібному питанні.
Девід,

Відповіді:


55

Ваше повідомлення правильне.

На жаль, якщо вам потрібно використовувати необов’язковий параметр у самому кінці списку параметрів, ви повинні вказати все до останнього параметра. Як правило, якщо ви хочете змішувати і збігати, ви надаєте їм значення за замовчуванням ''або null, і не використовуєте їх всередині функції, якщо вони є цим значенням за замовчуванням.


1
Можете навести приклад?
я я

2
@iamme зробити $limit = is_numeric($limit) ? $limit : '50';на початку GetData функції
Kamafeather

40

Немає способу "пропустити" аргумент, крім як вказати значення за замовчуванням, як falseабо null.

Оскільки PHP не має певного синтаксичного цукру, коли справа доходить до цього, ви часто бачите щось подібне:

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

Яка, як красномовно сказано в коментарях, використовує масиви для емуляції іменованих аргументів.

Це дає граничну гнучкість, але в деяких випадках може не знадобитися. Принаймні, ви можете перенести все, що, як вам здається, більшість часу не до кінця списку аргументів.


2
Я б визначив "щось подібне" як "використання масивів для емуляції іменованих аргументів", FWIW. :)
хаос

3
Незважаючи на більшу гнучкість, ви повинні пам’ятати параметри, які ви повинні / можете встановити (оскільки вони відсутні в підписі). Тож врешті-решт це може бути не таким корисним, як здається, але, звичайно, це залежить від контексту.
Фелікс Клінг

То яка найкраща практика для такого сценарію?
Адам Грант,

39

Ні, пропустити аргументи таким чином не можна. Ви можете пропустити передачу аргументів, лише якщо вони знаходяться в кінці списку параметрів.

Для цього була офіційна пропозиція: https://wiki.php.net/rfc/skipparams , яка відхилена. Сторінка пропозиції посилається на інші запитання щодо цієї теми.


Тоді як функції PHP мають необов’язкові параметри більше / менше?
я я

2
PHP підтримує значення параметрів за замовчуванням. Але ці параметри повинні бути в кінці списку.
Крістік,

1
Ви можете знайти приклади в документації PHP
Крістік

2
Ривки. Це мене так божеволіє. Якщо вам не подобається функція, яку запитує хтось інший, просто не використовуйте її. Інтернет найгірший часом.
Lee Saxon

@LeeSaxon питання полягає в читабельності та портативності. 1) Якщо хтось вирішить пропустити параметри, а хтось налагоджувальний код пропустить цей факт, виникає велика плутанина. 2) новий код не міг працювати на старих версіях без серйозного перебору, і ймовірність помилок була б дуже великою.
Марк Уолш,

6

Нічого не змінилося щодо можливості пропускати необов’язкові аргументи, однак для правильного синтаксису та можливості вказати 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');і будь-хто, хто викликає функцію в майбутньому, не повинен пам'ятати про за замовчуванням кожен раз або константу, оголошену для них.


1
Напевно, ви хотіли б суворого порівняння ($ limit === null)
roelleor

4

Проста відповідь - Ні . Але навіщо пропускати, коли перегрупування аргументів досягає цього?

Твоєю є " Неправильне використання аргументів функції за замовчуванням ", і вона не працюватиме, як ти очікуєш.

Додаткова примітка з документації 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, якщо це не визначено.


Це найкраща відповідь, оскільки вона забезпечує чітко проілюстровані синтаксичні пояснення! Дякую!
Крістіан

2

Для будь-якого пропущеного параметра (ви повинні) використовуйте параметр за замовчуванням, щоб бути в безпеці.

(Встановлення для null, де за замовчуванням є параметр `` або подібний, або навпаки, ви потрапите в біду ...)


2

Як уже згадувалося вище, ви не зможете пропустити параметри. Я написав цю відповідь, щоб надати якийсь додаток, який був занадто великим для розміщення в коментарі.

@Frank Nocke пропонує викликати функцію із параметрами за замовчуванням, наприклад, маючи

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

ви повинні використовувати

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

що функціонально буде таким самим, як і опускання перших двох ( $bі $c) параметрів.

Незрозуміло, які з них є типовими (є 0 вводиться, щоб вказати значення за замовчуванням, чи це важливо?).

Також існує небезпека того, що проблема зі значеннями за замовчуванням підключається до зовнішньої (або вбудованої) функції, коли значення за замовчуванням можуть бути змінені автором функції (або методу). Отже, якщо ви не хочете змінити свій дзвінок у програмі, ви можете ненавмисно змінити її поведінку.

Деякі обхідні шляхи можуть полягати у визначенні деяких глобальних констант, таких як DEFAULT_A_B"значення за промовчанням параметра B функції A" та "опущення" параметрів таким чином:

$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');найкращим варіантом буде дзвінок на подобається )


2

Ви не можете пропустити аргументи, але ви можете використовувати параметри масиву, і вам потрібно визначити лише 1 параметр, який є масивом параметрів.

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

І ви можете додати скільки завгодно параметрів, вам не потрібно їх визначати. Коли ви викликаєте функцію, ви встановлюєте свої параметри таким чином:

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

0

Ну, як і всі інші вже говорили, що те, що ви хочете, не буде можливим у 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


0

Встановіть ліміт на нуль

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

і викликати цю функцію

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

якщо ви хочете встановити ліміт, ви можете передати його як аргумент

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

0

Як радили раніше , нічого не змінилося. Однак будьте обережні, занадто багато параметрів (особливо необов’язкових) є сильним показником запаху коду.

Можливо, ваша функція робить занадто багато:

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

(що є лише прославленою версією менш формальної техніки масиву параметрів )

Іноді сама причина зробити параметр необов’язковим є неправильною. У цьому прикладі $pageнасправді має бути необов’язковим? Збереження пари символів насправді має значення?

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

Цей фрагмент:

    функція getData ($ name, $ options) {
       $ за замовчуванням = масив (
            'limit' => 50,
            'сторінка' => 2,
        );
        $ args = array_merge ($ за замовчуванням, $ параметри);
        print_r ($ args);
    }

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

Відповідь:

     Масив
    (
        [обмеження] => 50
        [сторінка] => 2
    )
    Масив
    (
        [межа] => 2
        [сторінка] => 2
    )
    Масив
    (
        [межа] => 10
        [сторінка] => 10
    )


2
Приємно. Але невелике пояснення було б корисним.
showdev

Гарна відповідь, але якщо ви хочете опустити необов’язковий параметр, зробіть це таким чином: функція getData ($ name, $ args = array ()) {$ defaults = array ('limit': => 50, 'page' => 2) ; $ args = array_merge ($ за замовчуванням, $ args); } Тепер цю функцію можна викликати лише з таким першим параметром: getData ('foo');
EchoSin

0

Ось що я б зробив:

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

?>

Сподіваюся, це комусь допоможе


0

Це своєрідне старе запитання з низкою технічно компетентних відповідей, але воно кричить про один із сучасних шаблонів дизайну в PHP: об’єктно-орієнтоване програмування. Замість того, щоб вводити колекцію примітивних скалярних типів даних, розгляньте можливість використання «injected-object», який містить усі дані, необхідні функції. http://php.net/manual/en/language.types.intro.php

Інжектований об'єкт може мати процедури перевірки властивостей і т. Д. Якщо інстанціювання та ін'єкція даних в ін'єктований об'єкт не може пройти всю перевірку, код може негайно створити виняток, і програма може уникнути незручного процесу роботи з потенційно неповними даними.

Ми можемо натякнути на введений об’єкт вловлювати помилки перед розгортанням. Деякі ідеї узагальнені в цій статті від кількох років тому.

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


0

Мені довелося зробити Factory з необов’язковими параметрами, моє обхідне рішення було використовувати нульовий оператор злиття:

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

Використання:

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

Не найкрасивіша річ, але це може бути гарний зразок для використання на заводах для тестів.



-2

Ви не можете пропустити середній параметр у своєму виклику функції. Але з цим можна обійтись:

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

Функція:

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

Я не впевнений, чому у вас є голоси проти, крім $ c, які також потребують значення за замовчуванням (ви не можете мати жодних необхідних аргументів після необов'язкового аргументу).
Френк Форте

-2

Як зазначив @IbrahimLawal. Кращою практикою є просто встановити для них nullзначення. Просто перевірте, чи передане значення nullвикористовує визначені за замовчуванням значення.

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

Сподіваюся, це допомагає.


Ви просто продублювали відповідь. Швидше ви могли б проголосувати чи прокоментувати це.
Ібрагім Лауал

-6
getData('some name');

просто не передайте їх, і буде прийнято значення за замовчуванням

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.