Bagaimana saya melewatkan argumen opsional dalam panggilan fungsi?

94

Oke, saya benar-benar lupa cara melewati argumen di PHP.

Katakanlah saya punya:

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

Bagaimana saya memanggil fungsi ini sehingga parameter tengah mengambil nilai default (mis. '50')?

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

Apakah hal di atas benar? Sepertinya aku tidak bisa membuat ini bekerja.

Chuck Le Butt
sumber
1
@Chuck untuk apa yang Anda cari sebenarnya? Seperti solusi atau kelas untuk menerapkan ini atau ...?
Rizier123
@ Rizier123 Saya menanyakan apakah versi PHP saat ini mendukung melewatkan argumen (seperti yang dilakukan bahasa lain). Jawaban saat ini mungkin sudah ketinggalan zaman. Dari deskripsi hadiah: "Jawaban saat ini berumur lima tahun. Apakah versi PHP saat ini mengubah banyak hal?"
Chuck Le Butt
1
@ Chuck Maka jawabannya mungkin: tidak ada yang berubah; tanpa solusi / kode Anda tidak akan mendapatkan fungsionalitas Anda.
Rizier123
Semua jawaban di sini tampaknya menganggap Anda memiliki kendali atas fungsi yang dipanggil. Jika fungsi itu adalah bagian dari pustaka atau kerangka kerja, Anda tidak memiliki opsi selain menentukan sesuatu untuk argumen 2 jika Anda memerlukan argumen 3. Satu-satunya opsi adalah mencari di sumber untuk fungsi dan mereplikasi nilai default.
Snapey
Tidak mungkin melewatkannya, tetapi Anda bisa meneruskan argumen default menggunakan ReflectionFunction. Saya memposting jawaban itu dalam pertanyaan serupa.
David

Jawaban:

55

Posting Anda benar.

Sayangnya, jika Anda perlu menggunakan parameter opsional di bagian paling akhir dari daftar parameter, Anda harus menentukan semuanya hingga parameter terakhir tersebut. Umumnya jika Anda ingin mencampur-dan-mencocokkan, Anda memberi mereka nilai default ''atau null, dan tidak menggunakannya di dalam fungsi jika nilai default tersebut.

zombat
sumber
1
Bisakah Anda memberikan contoh?
Saya adalah saya
2
@iamme lakukan $limit = is_numeric($limit) ? $limit : '50';pada awal fungsi getData
Kamafeather
40

Tidak ada cara untuk "melewati" argumen selain menentukan default like falseatau null.

Karena PHP kekurangan beberapa gula sintaksis dalam hal ini, Anda akan sering melihat sesuatu seperti ini:

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

Yang, seperti yang dengan fasih dikatakan di komentar, menggunakan array untuk meniru argumen bernama.

Ini memberikan fleksibilitas tertinggi tetapi mungkin tidak diperlukan dalam beberapa kasus. Paling tidak Anda dapat memindahkan apa pun yang menurut Anda tidak diharapkan pada sebagian besar waktu ke akhir daftar argumen.

Paolo Bergantino
sumber
2
Saya akan mengidentifikasi 'sesuatu seperti ini' sebagai 'menggunakan array untuk meniru argumen bernama', FWIW. :)
kekacauan
3
Meskipun lebih fleksibel, Anda harus mengingat parameter yang harus / dapat Anda setel (karena tidak ada dalam tanda tangan). Jadi pada akhirnya mungkin tidak berguna seperti yang terlihat tapi tentu saja ini tergantung pada konteksnya.
Felix Kling
Jadi apa praktik terbaik untuk skenario seperti itu?
Adam Grant
39

Tidak, tidak mungkin melewatkan argumen dengan cara ini. Anda dapat menghilangkan argumen yang lewat hanya jika argumen tersebut berada di akhir daftar parameter.

Ada proposal resmi untuk ini: https://wiki.php.net/rfc/skipparams , yang ditolak. Halaman proposal menautkan ke pertanyaan SO lainnya tentang topik ini.

Cristik
sumber
Lalu bagaimana fungsi PHP memiliki pilihan parameter more / less?
Saya adalah saya
2
PHP memiliki dukungan untuk nilai parameter default. Tetapi parameter tersebut harus berada di akhir daftar.
Cristik
1
Anda dapat menemukan contoh di dokumentasi PHP
Cristik
2
Brengsek. Membuatku sangat marah. Jika Anda tidak menyukai fitur yang diminta orang lain, jangan gunakan saja. Terkadang internet adalah yang terburuk.
Lee Saxon
@LeeSaxon masalahnya adalah keterbacaan dan portabilitas. 1) Jika seseorang memutuskan untuk melewati parameter, dan kode debug seseorang melewatkan fakta ini, terjadi kebingungan besar. 2) kode baru tidak dapat berfungsi pada versi lama tanpa over haul yang besar dan kemungkinan kesalahan akan sangat tinggi.
Mark Walsh
6

Tidak ada yang berubah mengenai kemampuan untuk melewati argumen opsional, namun untuk sintaks yang benar dan untuk dapat menentukan NULL untuk argumen yang ingin saya lewati, berikut cara saya melakukannya:

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

Ini dapat dipanggil demikian: getData('some name',NULL,'23');dan siapa pun yang memanggil fungsi di masa mendatang tidak perlu mengingat default setiap kali atau konstanta yang dideklarasikan untuk mereka.

Ibrahim Lawal
sumber
1
Anda mungkin ingin perbandingan yang ketat ($ limit === null)
roelleor
4

Jawaban sederhananya adalah Tidak . Tetapi mengapa melewatkan saat mengatur ulang argumen mencapai ini?

Milik Anda adalah " Penggunaan argumen fungsi default yang salah " dan tidak akan berfungsi seperti yang Anda harapkan.

Catatan tambahan dari dokumentasi PHP:

Saat menggunakan argumen default, default apa pun harus berada di sisi kanan argumen non-default; jika tidak, hal-hal tidak akan berfungsi seperti yang diharapkan.

Pertimbangkan hal berikut:

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

Outputnya adalah:

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

Penggunaan yang benar dari argumen fungsi default harus seperti ini:

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

Outputnya adalah:

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

Menempatkan default di kanan Anda setelah non-default memastikan bahwa itu akan selalu mengembalikan nilai default untuk variabel itu jika tidak ditentukan / diberikan Berikut adalah link untuk referensi dan dari mana contoh-contoh itu berasal.

Sunting: Menyetelnya nullseperti yang disarankan orang lain mungkin berhasil dan merupakan alternatif lain, tetapi mungkin tidak sesuai dengan apa yang Anda inginkan. Ini akan selalu mengatur default ke null jika tidak ditentukan.

Nelson Owalo
sumber
Ini adalah jawaban terbaik karena memberikan penjelasan sintaksis yang diilustrasikan dengan jelas! Terima kasih!
Christian
2

Untuk setiap parameter yang dilewati (Anda harus) pergi dengan parameter default, agar aman.

(Menetapkan untuk null di mana parameter default adalah '' atau serupa atau sebaliknya akan membuat Anda bermasalah ...)

Frank Nocke
sumber
2

Seperti disebutkan di atas, Anda tidak akan dapat melewati parameter. Saya telah menulis jawaban ini untuk memberikan beberapa tambahan, yang terlalu besar untuk dimasukkan dalam komentar.

@Frank Nocke mengusulkan untuk memanggil fungsi dengan parameter defaultnya, jadi misalnya memiliki

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

kamu harus menggunakan

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

yang secara fungsional akan sama dengan menghilangkan dua parameter ( $bdan $c) pertama.

Tidak jelas mana yang default ( 0diketik untuk memberikan nilai default, atau penting?).

Ada juga bahaya bahwa masalah nilai default terhubung ke fungsi eksternal (atau built-in), ketika nilai default dapat diubah oleh pembuat fungsi (atau metode). Jadi jika Anda tidak ingin mengubah panggilan Anda dalam program ini, Anda dapat secara tidak sengaja mengubah perilakunya.

Beberapa solusi mungkin untuk menentukan beberapa konstanta global, seperti DEFAULT_A_Byang akan menjadi "nilai default parameter B dari fungsi A" dan parameter "menghilangkan" dengan cara ini:

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

Untuk kelas, akan lebih mudah dan elegan jika Anda mendefinisikan konstanta kelas, karena mereka adalah bagian dari cakupan global, mis.

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.

Perhatikan bahwa konstanta default ini didefinisikan tepat satu kali di seluruh kode (bahkan tidak ada nilai dalam deklarasi metode), jadi jika terjadi beberapa perubahan yang tidak terduga, Anda akan selalu menyediakan fungsi / metode dengan nilai default yang benar.

Kejelasan dari solusi ini tentu saja lebih baik daripada memberikan nilai default mentah (seperti NULL, 0dll.) Yang tidak mengatakan apa-apa kepada pembaca.

(Saya setuju bahwa menelepon seperti $var = a(,,'ddd');akan menjadi pilihan terbaik)

Voitcus
sumber
2

Anda tidak dapat melewatkan argumen tetapi Anda dapat menggunakan parameter array dan Anda hanya perlu menentukan 1 parameter, yang merupakan array parameter.

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

Dan Anda dapat menambahkan sebanyak mungkin parameter yang Anda butuhkan, Anda tidak perlu menentukannya. Saat Anda memanggil fungsi tersebut, Anda meletakkan parameter Anda seperti ini:

myfunction(array("name" => "Bob","age" => "18", .........));
Vlad Isoc
sumber
0

Seperti yang sudah dikatakan orang lain, bahwa apa yang Anda inginkan tidak akan mungkin terjadi di PHP tanpa menambahkan baris kode apa pun di dalam fungsinya.

Tetapi Anda dapat menempatkan potongan kode ini di bagian atas fungsi untuk mendapatkan fungsionalitas Anda:

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

Jadi pada dasarnya dengan debug_backtrace()saya mendapatkan nama fungsi di mana kode ini ditempatkan, untuk kemudian membuat ReflectionFunctionobjek dan loop baru melalui semua argumen fungsi.

Dalam loop saya hanya memeriksa apakah argumen fungsi empty()DAN argumennya adalah "opsional" (berarti ia memiliki nilai default). Jika ya, saya cukup menetapkan nilai default ke argumen.

Demo

Rizier123
sumber
0

Tetapkan batas ke nol

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

dan memanggil fungsi itu

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

jika Anda ingin menyetel batas, Anda dapat meneruskan sebagai argumen

getData('some name', 50, '23');
Hari Kumar
sumber
0

Seperti yang disarankan sebelumnya , tidak ada yang berubah. Berhati-hatilah, terlalu banyak parameter (terutama yang opsional) merupakan indikator kuat dari code bau.

Mungkin fungsi Anda terlalu banyak:

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

Beberapa parameter dapat dikelompokkan secara logis:

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

Pilihan terakhir, Anda selalu dapat memasukkan objek parameter ad-hoc :

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

(yang hanya merupakan versi yang dimuliakan dari teknik parameter array yang kurang formal )

Terkadang, alasan untuk membuat parameter opsional salah. Dalam contoh ini, apakah $pagebenar - benar dimaksudkan sebagai opsional? Apakah menyimpan beberapa karakter benar-benar membuat perbedaan?

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

Cuplikan ini:

    function getData ($ nama, $ options) {
       $ default = larik (
            'batas' => 50,
            'halaman' => 2,
        );
        $ args = array_merge ($ default, $ opsi);
        print_r ($ args);
    }

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

Jawabannya adalah:

     Himpunan
    (
        [batas] => 50
        [laman] => 2
    )
    Himpunan
    (
        [batas] => 2
        [laman] => 2
    )
    Himpunan
    (
        [batas] => 10
        [laman] => 10
    )

tidak ada0day
sumber
2
Bagus. Tetapi sedikit penjelasan akan membantu.
showdev
Jawaban bagus, tetapi jika Anda ingin menghilangkan parameter opsional lakukan dengan cara ini: function getData ($ name, $ args = array ()) {$ defaults = array ('limit': => 50, 'page' => 2) ; $ args = array_merge ($ defaults, $ args); } Sekarang dimungkinkan untuk memanggil fungsi ini hanya dengan parameter pertama seperti ini: getData ('foo');
EchoSin
0

Inilah yang akan saya lakukan:

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

?>

Semoga ini bisa membantu seseorang

Michael Eugene Yuen
sumber
0

Ini adalah jenis pertanyaan lama dengan sejumlah jawaban yang secara teknis kompeten, tetapi ini merupakan salah satu pola desain modern dalam PHP: Pemrograman Berorientasi Objek. Daripada memasukkan kumpulan tipe data skalar primitif, pertimbangkan untuk menggunakan "objek yang diinjeksi" yang berisi semua data yang dibutuhkan oleh fungsi. http://php.net/manual/en/language.types.intro.php

Objek yang diinjeksi mungkin memiliki rutinitas validasi properti, dll. Jika instansiasi dan injeksi data ke dalam objek yang diinjeksi tidak dapat melewati semua validasi, kode dapat langsung mengeluarkan pengecualian dan aplikasi dapat menghindari proses transaksi yang canggung. dengan data yang berpotensi tidak lengkap.

Kita bisa memberi petunjuk pada objek yang diinjeksi untuk mendeteksi kesalahan sebelum penerapan. Beberapa ide dirangkum dalam artikel ini dari beberapa tahun yang lalu.

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

Ray Paseur
sumber
0

Saya harus membuat Pabrik dengan parameter opsional, solusi saya adalah menggunakan operator penggabungan nol:

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 ?? '[email protected]';
    $subject    = $subject ?? 'Some subject';
    $message    = $message ?? 'Some message';
}

Pemakaian:

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

Bukan yang tercantik, tapi mungkin pola yang baik untuk digunakan di Pabrik untuk pengujian.

Lucas Bustamante
sumber
-1

Coba ini.

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

getData('some name', '', '23');
Dev Danidhariya
sumber
-2

Anda tidak dapat melewatkan parameter tengah dalam pemanggilan fungsi Anda. Tapi, Anda bisa menyiasatinya dengan ini:

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

Fungsi:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}
Ronak Patel
sumber
Saya tidak yakin mengapa Anda memiliki suara rendah, selain $ c juga membutuhkan nilai default (Anda tidak dapat memiliki argumen yang diperlukan setelah argumen opsional).
Frank Forte
-2

Seperti yang ditunjukkan @IbrahimLawal. Praktik terbaik adalah mengaturnya ke nullnilai. Cukup periksa apakah nilai yang diteruskan nulldi mana Anda menggunakan default yang Anda tentukan.

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

Semoga ini membantu.

asp.patrickg
sumber
Anda hanya menduplikasi tanggapannya. Sebaliknya Anda dapat memberi suara positif atau mengomentarinya.
Ibrahim Lawal
-6
getData('some name');

hanya saja, jangan melewatkannya dan nilai default akan diterima

Shal
sumber