Nhiều đối số trong hàm gọi so với mảng đơn


24

Tôi có một hàm lấy một tập các tham số, sau đó áp dụng cho chúng làm điều kiện cho truy vấn SQL. Tuy nhiên, trong khi tôi ủng hộ một mảng đối số duy nhất chứa các điều kiện:

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

Thay vào đó, đồng nghiệp của tôi thích liệt kê tất cả các đối số một cách rõ ràng:

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

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

Lập luận của ông là bằng cách liệt kê các đối số một cách rõ ràng, hành vi của hàm trở nên rõ ràng hơn - trái ngược với việc phải đi sâu vào mã để tìm hiểu xem đối số bí ẩn $paramlà gì.

Vấn đề của tôi là điều này trở nên rất dài dòng khi xử lý nhiều tranh luận, như 10+. Có thực hành ưa thích? Trường hợp xấu nhất của tôi sẽ là một cái gì đó như sau:

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


1
Nếu hàm mong đợi các khóa cụ thể làm tham số, thì ít nhất các khóa đó phải được ghi lại trong DocBlock - theo cách đó IDE có thể hiển thị thông tin liên quan mà không cần phải đi sâu vào mã. vi.wikipedia.org/wiki/PHPDoc
Ilari Kajaste

2
Mẹo hiệu suất: Không foreachcần thiết trong trường hợp này, bạn có thể sử dụng if(!empty($params['name']))thay vì foreachswitch.
chiborg

1
Bây giờ bạn có một phương pháp mà bạn sử dụng. Tôi muốn đề nghị xem ở đây: book.cakephp.org/2.0/en/models/iêu để tạo thêm phương thức. Chúng thậm chí có thể được tạo ra một cách kỳ diệu cho các phát hiện tiêu chuẩn và được phát triển tùy chỉnh cho các tìm kiếm cụ thể. Nói chung mà làm cho một api rõ ràng cho người dùng của mô hình.
Luc Franken


2
Một lưu ý về 'mẹo hiệu suất' ở trên: không được sử dụng một cách mù quáng !empty($params['name'])để kiểm tra các tham số - ví dụ: chuỗi "0" sẽ trống. Tốt hơn là sử dụng array_key_existsđể kiểm tra chìa khóa hoặc issetnếu bạn không quan tâm null.
AmadeusDrZaius

Câu trả lời:


27

IMHO đồng nghiệp của bạn là chính xác cho ví dụ trên. Sở thích của bạn có thể là ngắn gọn, nhưng nó cũng ít đọc hơn và do đó ít bảo trì hơn. Đặt câu hỏi tại sao phải viết chức năng ở vị trí đầu tiên, chức năng của bạn 'mang đến cái gì' - Tôi phải hiểu nó làm gì và làm thế nào, rất chi tiết, chỉ để sử dụng nó. Với ví dụ của anh ấy, mặc dù tôi không phải là lập trình viên PHP, tôi có thể thấy đủ chi tiết trong khai báo hàm mà tôi không phải lo lắng về việc triển khai nó.

Theo như một số lượng lớn hơn các đối số, thường được coi là một mùi mã. Điển hình là chức năng đang cố gắng làm quá nhiều? Nếu bạn tìm thấy một nhu cầu thực sự cho một số lượng lớn các đối số, thì có khả năng chúng có liên quan theo một cách nào đó và thuộc về nhau trong một hoặc một vài cấu trúc hoặc lớp (thậm chí có thể là mảng các mục liên quan như đường trong một địa chỉ). Tuy nhiên, việc truyền một mảng không có cấu trúc sẽ không có gì để giải quyết mã có mùi.


Đối với nhu cầu của một số lượng lớn các đối số, hàm về cơ bản là không có hoặc nhiều đối số, và sau đó giới hạn kết quả được đặt bởi các đối số đó. Bản thân các đối số không liên quan nhiều đến nhau (như các mệnh đề SQL riêng biệt) và thậm chí có thể không có cùng cấu trúc (một có thể là một WHERE đơn giản, nhưng một điều khác sẽ yêu cầu một số THAM GIA ngoài WHERE). Nó vẫn sẽ được coi là một mùi mã trong trường hợp cụ thể này?
xiankai

2
@xiankai Trong ví dụ đó, tôi có thể tạo một tham wheresố mảng cho các đối số, một cho các joinchỉ định, v.v. Bằng cách đặt tên cho chúng một cách thích hợp mà vẫn có thể tự ghi lại.
Jan Doggen

Điều gì xảy ra nếu tôi sử dụng setter / getter thay vào đó và tôi hoàn toàn không vượt qua đối số? Đó có phải là một thực hành xấu? Nó không phải là một mục đích của việc sử dụng setter / getter?
lyhong

Tôi sẽ thách thức rằng sở thích của OP là "ít đọc hơn" (như thế nào?) Và ít bảo trì hơn. searchQuery ('', '', '', '', 'foo', '', '', '', 'bar') ít có thể đọc hoặc duy trì hơn nhiều so với searchQuery (['q' => 'foo', 'x' => 'bar']) Một số lượng lớn các đối số không nhất thiết phải là mùi mã; một truy vấn (), ví dụ. Và ngay cả đối với một số lượng nhỏ hơn các đối số, việc thiếu tính nhất quán trong thứ tự đối số xảy ra khi các đối số được truyền trực tiếp minh họa ý tưởng tồi đối với các tham số mã cứng. Chỉ cần nhìn vào các hàm chuỗi và mảng trong PHP để biết sự không nhất quán.
MikeSchinkel

4

Câu trả lời của tôi là ít nhiều ngôn ngữ bất khả tri.

Nếu mục đích duy nhất của việc nhóm các đối số trong một cấu trúc dữ liệu phức tạp (bảng, bản ghi, từ điển, đối tượng ...) là để chuyển toàn bộ chúng cho một hàm, tốt hơn là tránh nó. Điều này thêm một lớp phức tạp vô dụng và làm cho ý định của bạn bị che khuất.

Nếu các đối số được nhóm có một ý nghĩa riêng, thì lớp phức tạp đó sẽ giúp hiểu toàn bộ thiết kế: thay vào đó là lớp trừu tượng.

Bạn có thể thấy rằng thay vì một tá các đối số riêng lẻ hoặc một mảng lớn, thiết kế tốt nhất là với hai hoặc ba đối số mỗi nhóm dữ liệu tương quan.


1

Trong trường hợp của bạn, tôi thích phương pháp của đồng nghiệp của bạn. Nếu bạn đang viết mô hình và tôi đang sử dụng mô hình của bạn để phát triển chúng. Tôi thấy chữ ký của phương pháp của đồng nghiệp của bạn và có thể sử dụng nó ngay lập tức.

Trong khi, tôi sẽ phải thực hiện searchQuerychức năng của bạn để xem những tham số nào được chức năng của bạn mong đợi.

Tôi chỉ thích cách tiếp cận của bạn trong trường hợp khi searchQuerygiới hạn chỉ tìm kiếm trong một bảng duy nhất, vì vậy sẽ không có tham gia. Trong trường hợp đó, chức năng của tôi sẽ trông như thế này:

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

Vì vậy, tôi biết ngay rằng các phần tử của mảng thực sự là tên cột của một bảng cụ thể mà lớp có phương thức này đại diện trong mã của bạn.


1

Làm cả hai, sắp xếp. array_mergecho phép một danh sách rõ ràng ở đầu chức năng, như đồng nghiệp của bạn thích, trong khi giữ cho các tham số không bị khó sử dụng, như bạn muốn.

Tôi cũng đề nghị sử dụng đề xuất của @ chiborg từ các nhận xét câu hỏi - rõ ràng hơn nhiều những gì bạn dự định.

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

Ngoài ra, bạn có thể chuyển một chuỗi giống như chuỗi truy vấn và sử dụng parse_str(vì có vẻ như bạn đang sử dụng PHP, nhưng các giải pháp khác có thể có sẵn bằng các ngôn ngữ khác) để xử lý chuỗi đó thành một mảng bên trong phương thức:

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

và gọi nó như

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

Bạn có thể sử dụng http_build_queryđể chuyển đổi từ một mảng kết hợp thành một chuỗi (ngược lại parse_str).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.