Berbagai argumen dalam panggilan fungsi vs array tunggal

24

Saya memiliki fungsi yang mengambil set parameter, kemudian berlaku untuk mereka sebagai syarat untuk query SQL. Namun, sementara saya memilih array argumen tunggal yang berisi kondisi itu sendiri:

function searchQuery($params = array()) {
    foreach($params as $param => $value) {
        switch ($param) {
            case 'name':
                $query->where('name', $value);
                break;
            case 'phone':
                $query->join('phone');
                $query->where('phone', $value);
                break;
        }
    }
}

Rekan saya lebih suka mendaftarkan semua argumen secara eksplisit sebagai gantinya:

function searchQuery($name = '', $phone = '') {
    if ($name) {
        $query->where('name', $value);
    }

    if ($phone) {
        $query->join('phone');
        $query->where('phone', $value);
    }
}

Argumennya adalah bahwa dengan mendaftar argumen secara eksplisit, perilaku fungsi menjadi lebih jelas - sebagai lawan harus mempelajari kode untuk mencari tahu apa argumen misterius $paramitu.

Masalah saya adalah ini menjadi sangat bertele-tele ketika berhadapan dengan banyak argumen, seperti 10+. Apakah ada praktik yang disukai? Skenario terburuk saya akan melihat sesuatu seperti berikut:

searchQuery('', '', '', '', '', '', '', '', '', '', '', '', 'search_query')

xiankai
sumber
1
Jika fungsi mengharapkan kunci spesifik sebagai parameter, setidaknya kunci-kunci itu harus didokumentasikan dalam DocBlock - dengan cara itu IDE dapat menampilkan informasi yang relevan tanpa harus mempelajari kode. en.wikipedia.org/wiki/PHPDoc
Ilari Kajaste
2
Kiat kinerja: Dalam hal foreachini tidak perlu, Anda bisa menggunakan if(!empty($params['name']))alih-alih foreachdan switch.
chiborg
1
Anda sekarang memiliki satu metode yang Anda gunakan. Saya akan menyarankan untuk melihat di sini: book.cakephp.org/2.0/en/models/… untuk membuat lebih banyak metode. Mereka bahkan dapat dihasilkan secara ajaib untuk penemuan standar dan dikembangkan di kustom untuk pencarian tertentu. Secara umum itu membuat api yang jelas untuk para pengguna model.
Luc Franken
2
Catatan pada 'tip kinerja' di atas: jangan gunakan secara membabi buta !empty($params['name'])untuk menguji parameter - misalnya, string "0" akan kosong. Lebih baik digunakan array_key_existsuntuk memeriksa kunci, atau issetjika Anda tidak peduli null.
AmadeusDrZaius

Jawaban:

27

IMHO kolega Anda sudah benar untuk contoh di atas. Preferensi Anda mungkin singkat, tetapi juga kurang dapat dibaca dan karenanya kurang dapat dipertahankan. Ajukan pertanyaan mengapa repot-repot menulis fungsi di tempat pertama, apa fungsi Anda 'bawa ke meja'- Saya harus memahami apa fungsinya dan bagaimana melakukannya, secara sangat rinci, hanya untuk menggunakannya. Dengan contohnya, meskipun saya bukan seorang programmer PHP, saya dapat melihat cukup detail dalam deklarasi fungsi sehingga saya tidak perlu khawatir dengan implementasinya.

Sejauh sejumlah besar argumen, itu biasanya dianggap sebagai bau kode. Biasanya fungsi ini mencoba melakukan terlalu banyak? Jika Anda benar-benar menemukan kebutuhan untuk sejumlah besar argumen, kemungkinan mereka terkait dalam beberapa cara dan termasuk bersama dalam satu atau beberapa struktur atau kelas (bahkan mungkin berbagai item terkait seperti baris dalam alamat). Namun, melewatkan array yang tidak terstruktur tidak menyebabkan bau kode.

mattnz
sumber
Adapun kebutuhan sejumlah besar argumen, fungsi dasarnya mengambil nol atau lebih argumen, dan kemudian membatasi hasil yang ditetapkan oleh argumen tersebut. Argumen itu sendiri tidak memiliki banyak hubungannya dengan satu sama lain (sebagai klausa SQL yang berbeda), dan bahkan mungkin tidak memiliki struktur yang sama (satu dapat menjadi sederhana DI MANA, tetapi yang lain akan membutuhkan beberapa GABUNGAN di samping WHERE). Apakah masih dianggap sebagai bau kode dalam kasus khusus ini?
xiankai
2
@xiankai Dalam contoh itu saya mungkin akan membuat satu param array untuk whereargumen, satu untuk joinpenspesifikasi dll. Dengan memberi nama mereka dengan tepat yang masih akan mendokumentasikan diri.
Jan Doggen
Bagaimana jika saya menggunakan setter / pengambil dan saya tidak memberikan argumen sama sekali? Apakah ini praktik yang buruk? Apakah ini bukan tujuan menggunakan setter / pengambil?
lyhong
Saya akan menantang bahwa preferensi OP "kurang dapat dibaca" (bagaimana?) Dan kurang dapat dipertahankan. searchQuery ('', '', '', '', 'foo', '', '', '', 'bar') jauh lebih mudah dibaca atau dikelola daripada searchQuery (['q' => 'foo', 'x' => 'bar']) Sejumlah besar argumen juga tidak harus berupa bau kode; kueri (), misalnya. Dan bahkan untuk jumlah argumen yang lebih sedikit, kurangnya konsistensi dalam urutan argumen yang terjadi ketika argumen disahkan secara langsung menggambarkan betapa ide buruk itu adalah parameter hardcode. Lihat saja fungsi string dan array di PHP untuk kata inkonsistensi.
MikeSchinkel
4

Jawaban saya kurang lebih agnostik bahasa.

Jika satu-satunya tujuan pengelompokan argumen dalam struktur data yang kompleks (tabel, catatan, kamus, objek ...) adalah meneruskannya secara keseluruhan ke suatu fungsi, lebih baik menghindarinya. Ini menambah lapisan kompleksitas yang tidak berguna dan membuat niat Anda menjadi tidak jelas.

Jika argumen yang dikelompokkan memiliki makna sendiri, maka lapisan kompleksitas membantu memahami keseluruhan desain: sebagai gantinya beri nama layer abstraksi.

Anda mungkin menemukan bahwa alih-alih selusin argumen individual atau satu array besar, desain terbaik adalah dengan dua atau tiga argumen yang masing-masing mengelompokkan data yang berkorelasi.

mouviciel
sumber
1

Dalam kasus Anda, saya lebih suka metode kolega Anda. Jika Anda menulis model dan saya menggunakan model Anda untuk mengembangkannya. Saya melihat tanda tangan metode kolega Anda dan dapat segera menggunakannya.

Sementara, saya harus melalui implementasi searchQueryfungsi Anda untuk melihat parameter apa yang diharapkan oleh fungsi Anda.

Saya lebih suka pendekatan Anda hanya dalam kasus ketika searchQueryterbatas hanya mencari dalam satu tabel, sehingga tidak akan ada bergabung. Dalam hal ini fungsi saya akan terlihat seperti ini:

function searchQuery($params = array()) {
    foreach($params as $param => $value) {
        $query->where($param, $value);
    }
} 

Jadi, saya segera tahu bahwa elemen-elemen array sebenarnya adalah nama-nama kolom dari tabel tertentu yang diwakili oleh kelas yang memiliki metode ini dalam kode Anda.

Ozair Kafray
sumber
1

Lakukan keduanya, semacam. array_mergememungkinkan daftar eksplisit di bagian atas fungsi, seperti yang disukai rekan kerja Anda, sambil menjaga agar parameter tidak menjadi berat, seperti yang Anda inginkan.

Saya juga sangat menyarankan menggunakan saran @ chiborg dari komentar pertanyaan - itu jauh lebih jelas apa yang Anda inginkan.

function searchQuery($params = array()) {
    $defaults = array(
        'name' => '',
        'phone' => '',
        ....
    );
    $params = array_merge($defaults, $params);

    if(!empty($params['name'])) {
        $query->where('name', $params['name']);
    }
    if (!empty($params['phone'])) {
        $query->join('phone');
        $query->where('phone', $params['phone']);
    }
    ....
}
Izkata
sumber
0

Anda juga bisa melewatkan string yang menyerupai string kueri, dan menggunakan parse_str(karena sepertinya Anda menggunakan PHP, tetapi solusi lain mungkin tersedia dalam bahasa lain) untuk memprosesnya menjadi array di dalam metode:

/**
 * Executes a search in the DB with the constraints specified in the $queryString
 * @var $queryString string The search parameters in a query string format (ie
 *      "foo=abc&bar=hello"
 * @return ResultSet the result set of performing the query
 */
function searchQuery($queryString) {
  $params = parse_str($queryString);
  if (isset($params['name'])) {
    $query->where('name', $params['name']);
  }
  if (isset($params['phone'])) {
    $query->join('phone');
    $query->where('phone', $params['phone']);
  }
  ...

  return ...;
}

dan menyebutnya seperti

$result = searchQuery('name=foo&phone=555-123-456');

Anda dapat menggunakan http_build_queryuntuk mengonversi dari array asosiatif ke string (kebalikan yang parse_strterjadi).

Carlos Campderrós
sumber