Tek tek dizi vs işlev çağrısında birden fazla bağımsız değişken


24

Bir parametreler kümesinde yer alan ve ardından bir SQL sorgusuna koşul olarak uygulanan bir işleve sahibim. Bununla birlikte, koşulları içeren tek bir argüman dizisini tercih ederken:

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

Meslektaşım açıkça tüm argümanları listelemeyi tercih etti:

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

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

Argümanı, argümanları açıkça listeleyerek, fonksiyonun davranışının daha belirgin hale gelmesiydi - gizemli argümanın ne olduğunu bulmak için koda atlamak zorunda kalmanın aksine $param.

Benim sorunum, 10+ gibi birçok argümanla uğraşırken bunun çok ayrıntılı olmasıydı. Tercih edilen bir uygulama var mı? Benim en kötü senaryom, şöyle bir şey görmek olacaktır:

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


1
İşlev, özel anahtarları parametre olarak beklerse, en azından bu tuşların bir DocBlock'ta belgelenmesi gerekir - bu şekilde IDE'ler ilgili bilgileri koda girmeden gösterebilir. en.wikipedia.org/wiki/PHPDoc
Ilari Kajaste

2
Performans ipucu: foreachgereksizdir bu durumda şunu kullanabilirsiniz if(!empty($params['name']))yerine foreachve switch.
chiborg

1
Artık kullandığınız bir yöntem var. Buraya bir göz atmanızı öneririm: daha fazla yöntem oluşturmak için book.cakephp.org/2.0/en/models/… . Hatta standart aramalar için sihirli bir şekilde oluşturulabilir ve belirli aramalar için özel olarak geliştirilebilir. Genel olarak bu model kullanıcıları için net bir api yapar.
Luc Franken


2
Yukarıdaki 'performans ipucu' ile ilgili bir not: !empty($params['name'])parametreleri test etmek için kör kullanmayın - örneğin, "0" dizesi boş kalır. array_key_existsAnahtarı kontrol etmek için ya issetda umursamıyorsanız kullanmak daha iyidir null.
AmadeusDrZaius

Yanıtlar:


27

IMHO meslektaşınız yukarıdaki örnek için doğrudur. Tercihiniz kısa olabilir, ancak aynı zamanda daha az okunabilir ve bu nedenle daha az bakım yapılabilir. Fonksiyonu neden ilk olarak yazarken neden rahatsız edici, 'fonksiyonunuz masaya ne getiriyor' sorusunu sorun - ne yaptığını ve nasıl yaptığını, sadece onu kullanmak için ne kadar ayrıntılı olduğunu anlamak zorundayım. Onun örneğiyle, bir PHP programcısı olmasam bile, işlev bildirimi içerisinde kendimi uygulamasıyla ilgilenmek zorunda kalmayacağım kadar ayrıntı görebiliyorum.

Argüman sayısı kadar, normalde bir kod kokusu olarak kabul edilir. Genelde işlev çok fazla şey yapmaya mı çalışıyor? Çok sayıda argümana gerçek bir ihtiyaç bulursanız, bir şekilde ilişkili olmaları ve bir veya birkaç yapı veya sınıfta bir araya gelmeleri muhtemeldir (belki bir adresdeki satırlar gibi ilgili öğelerin dizisi). Ancak, yapılandırılmamış bir diziyi iletmek, kod kokularını gidermek için hiçbir şey yapmaz.


Çok sayıda argümana ihtiyaç duyulduğunda, işlev aslında sıfır veya daha fazla argüman alıyor ve ardından bu argümanlar tarafından belirlenen sonucu sınırlıyor. Argümanların birbirleriyle pek ilgileri yoktur (farklı SQL cümleleri gibi) ve aynı yapıya bile sahip olmayabilirler (biri basit bir NEREDE olabilir, ama bir diğeri NEREDE'ye ek olarak birkaç JOIN gerektirir). Bu özel durumda hala bir kod kokusu olarak kabul edilir mi?
xiankai

2
@xiankai Bu örnekte, belki whereargümanlar için, biri tanımlayıcılar vb. için bir dizi param yapabilirim join.
Jan Doggen

Ya setter / getter yerine kullanırsam ve tartışmayı geçemezsem ne olur? Kötü bir uygulama mı? Setter / getter kullanmak için bir amaç değil mi?
lyhong

OP'nin tercihinin "daha az okunabilir" (nasıl?) Ve daha az bakım gerektirebileceğini düşünüyorum. searchQuery ('', '', '', '', 'foo', '', '', '', 'bar') searchQuery'den (['q' => 'foo', 'x' => 'bar']) Çok sayıda argüman zorunlu olarak bir kod kokusudur; örneğin bir sorgu (). Ve daha az sayıda argüman için bile, argümanlar doğrudan iletildiğinde ortaya çıkan argüman sırasındaki tutarlılık eksikliği, parametreleri kodlamanın ne kadar kötü bir fikir olduğunu gösterir. PHP'deki dizge ve dizi işlevlerine sadece tutarsızlık için bakmanız yeterli.
MikeSchinkel

4

Cevabım aşağı yukarı dil agnostik.

Argümanları karmaşık bir veri yapısında (tablo, kayıt, sözlük, nesne ...) gruplandırmanın tek amacı onları bir fonksiyona bir bütün olarak iletmekse, bundan kaçınmak daha iyidir. Bu işe yaramaz bir karmaşıklık katmanı ekler ve niyetinizi belirsizleştirir.

Eğer gruplanmış argümanlar kendi başlarına bir anlam ifade ediyorsa, o zaman bu karmaşıklık katmanı tüm tasarımın anlaşılmasına yardımcı olur: bunun yerine soyutlama katmanını adlandırın.

Bir düzine bağımsız argüman veya bir büyük dizi yerine, en iyi tasarımın her biriyle ilişkili verileri gruplayan iki veya üç argüman olduğunu görebilirsiniz.


1

Senin durumunda, meslektaşının yöntemini tercih ederim. Modeller yazıyorsan ve ben onların modellerini onların üzerinde geliştirmek için kullanıyordum. İş arkadaşınızın yönteminin imzasını görüyorum ve hemen kullanabiliyorum.

Bununla birlikte, searchQueryfonksiyonunuzdan hangi parametrelerin beklendiğini görmek için fonksiyonunuzun uygulanmasından geçmem gerekecekti .

Yaklaşımınızı yalnızca searchQuerytek bir tablo içinde arama yapmakla sınırlı kalması durumunda tercih ederim , bu nedenle katılım olmaz. Bu durumda fonksiyonum şöyle görünür:

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

Bu yüzden, dizi öğelerinin gerçekte, bu yönteme sahip olan sınıfın kodunuzda temsil ettiği belirli bir tablonun sütun adları olduğunu hemen biliyorum .


1

İkisini birden yap. array_mergeiş arkadaşınızın sevdiği gibi, parametreleri tercih ettiğiniz gibi parametreleri dengesiz tutmaktan koruyarak işlevin en üstünde açık bir listeye izin verir.

Ayrıca, @ chiborg'un önerisini soru yorumlarından kullanmanızı şiddetle tavsiye ediyorum - ne düşündüğünüzü çok daha açık bir şekilde.

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']);
    }
    ....
}

0

Ayrıca, bir sorgu dizisine benzeyen bir dize iletebilir ve parse_str(PHP kullanıyormuş gibi göründüğünüzden, ancak diğer çözümler muhtemelen diğer dillerde de kullanılabilir) yöntemde bir dizide işlemek için kullanabilirsiniz:

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

ve buna benziyor

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

http_build_queryBir ilişkisel diziden bir dizgeye (tersini yapan parse_str) dönüştürmek için kullanabilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.