2012-04-17 22 views
10

Tôi thích tạo các hàm PHP bằng cách sử dụng các cặp key => giá trị (mảng) làm đối số thay vì các tham số riêng lẻ.Các đối số hàm PHP - Sử dụng một mảng hay không?

Ví dụ, tôi thích:

function useless_func($params) { 
    if (!isset($params['text'])) { $params['text'] = "default text"; }  
    if (!isset($params['text2'])) { $params['text2'] = "default text2"; } 
    if (!isset($params['text3'])) { $params['text3'] = "default text3"; } 
    echo $params['text'].$params['text2'].$params['text3']; 
    return; 
} 

Và tôi không thích: những điều

function useless_func($text = "default text", $text2 = "default text2", $text3 = "default text3") { 
     echo $text.$text2.$text3; 
    return; 
} 

tôi đã nhìn thấy đầu tiên thực hiện theo cách này rộng rãi trong codebase Wordpress.

Lý do tôi thích mảng:

  • luận Chức năng có thể được cung cấp trong bất kỳ thứ tự
  • dễ dàng hơn để đọc mã/nhiều tự chủ tài liệu (theo ý kiến ​​của tôi)
  • Ít dễ bị lỗi, bởi vì khi gọi một hàm Tôi phải điều tra các khóa mảng phù hợp

Tôi đang thảo luận điều này với một đồng nghiệp và nói rằng nó vô dụng và chỉ dẫn đến mã phụ và khó hơn nhiều để đặt giá trị mặc định. Về cơ bản, anh ấy không đồng ý với tôi hoàn toàn về cả ba điểm.

Tôi đang tìm một số lời khuyên và hướng dẫn chung từ các chuyên gia có thể cung cấp thông tin chi tiết: Cách tốt hơn hoặc phù hợp hơn để thực hiện việc này là gì?

+0

Tôi không hiểu tại sao mọi người lại chống lại nó theo cách bạn đã đề cập. Tôi nghĩ đó là cách linh hoạt, ngay cả khi ai đó đang làm việc với chức năng của bạn. Tôi đang phát triển một khung công tác có raw_queries và một vài nhiều thứ hơn.Và khả năng phân tích một mảng các tham số làm cho nó rất linh hoạt. – DaAmidza

Trả lời

15

Vâng, thật là hữu ích. Nhưng đối với một số đối số được truyền đi luôn tốt hơn là sử dụng tính năng chuyển cổ điển như function some($a1, $a2). Tôi đang làm như thế này trong mã của tôi:

function getSome(SomeClass $object, array $options = array()) 
{ 
    // $object is required to be an instance of SomeClass, and there's no need to get element by key, then check if it's an object and it's an instance of SomeClass 

    // Set defaults for all passed options 
    $options = array_merge(array(
     'property1' => 'default1', 
     'property2' => 'default2', 
     ... => ... 
    ), $options); 
} 

Vì vậy, như bạn có thể thấy tôi thích điều đó phong cách mã quá, nhưng đối với lõi lập luận tôi thích phong cách cổ điển, vì như vậy PHP kiểm soát nhiều điều mà tôi nên , nếu tôi sử dụng kiểu mã của bạn.

+0

"cốt lõi" đối số là chủ quan và có thể dẫn đến một danh sách xmas của args. Nếu bạn làm theo quy tắc cứng và nhanh hơn 2, phải là một mảng, bất kể lõi hay không. –

0

Đồng nghiệp của bạn bị điên. Nó hoàn toàn chấp nhận được để truyền vào một mảng như một đối số hàm. Nó phổ biến trong nhiều ứng dụng nguồn mở bao gồm Symfony và Doctrine. Tôi đã luôn luôn tuân theo quy tắc 2 đối số, nếu một hàm cần nhiều hơn hai đối số, HOẶC bạn nghĩ rằng nó sẽ sử dụng nhiều hơn hai đối số trong tương lai, hãy sử dụng một mảng. IMO cho phép tính linh hoạt nhất và giảm bất kỳ lỗi mã gọi nào có thể phát sinh nếu đối số được truyền không chính xác. Chắc chắn phải mất một chút công việc để ngoại suy các giá trị từ mảng, và bạn phải tính đến các phần tử cần thiết, nhưng nó làm cho việc thêm các tính năng dễ dàng hơn nhiều, và tốt hơn nhiều so với truyền 13 đối số cho hàm mỗi lần nó cần được gọi.

Dưới đây là một đoạn mã hiển thị theo yêu cầu vs params tùy chọn chỉ để cung cấp cho bạn một ý tưởng:

// Class will tokenize a string based on params 
public static function tokenize(array $params) 
{ 
    // Validate required elements 
    if (!array_key_exists('value', $params)) { 
     throw new Exception(sprintf('Invalid $value: %s', serialize($params))); 
    }   

    // Localize optional elements 
    $value   = $params['value']; 
    $separator  = (array_key_exists('separator', $params)) ? $params['separator'] : '-'; 
    $urlEncode  = (array_key_exists('urlEncode', $params)) ? $params['urlEncode'] : false; 
    $allowedChars  = (array_key_exists('allowedChars', $params)) ? $params['allowedChars'] : array(); 
    $charsToRemove = (array_key_exists('charsToRemove', $params)) ? $params['charsToRemove'] : array(); 

.... 
5

đồng nghiệp của bạn là đúng. Không chỉ là mã nhiều hơn cho cùng một chức năng, khó đọc hơn và có lẽ đã giảm hiệu suất (Vì bạn cần gọi isset cho mỗi thông số và bạn cần truy cập một mảng để đặt giá trị).

+0

Bạn có thấy @devdRew ở trên không, bạn có nói rằng hàm array_merge() sẽ vẫn giữ nước cho "chậm" không? – ethanpil

+0

Đó là loại "chiến tranh holly", sử dụng hoặc không sử dụng tổng hợp trong các đối số mảng, nhưng nếu bạn nói đơn giản hơn để sử dụng các đối số riêng biệt, ví dụ như lưu trữ một số bản ghi vào cơ sở dữ liệu sử dụng cho mỗi giá trị hàng như một đối số riêng biệt. Đúng? – devdRew

9

tôi giả sử bạn đang yêu cầu cho dù đó là A Good Thing viết tất cả chức năng để họ chỉ chấp nhận một đối số, và cho lập luận rằng để trở thành một mảng?

Nếu bạn là người duy nhất sẽ làm việc với mã của bạn thì bạn có thể làm những gì bạn thích. Tuy nhiên, bằng cách chuyển tất cả các giá trị đối số thông qua một mảng, bất kỳ ai khác sẽ phải làm việc chăm chỉ hơn để hiểu chức năng của nó là gì và tại sao/chúng có thể sử dụng nó như thế nào, đặc biệt nếu chúng đang sử dụng IDE với chức năng tự động hoàn thành vv Họ không gọi nó là một "chữ ký chức năng" cho không có gì.

Tôi muốn đề xuất tham số mảng được dành riêng cho các mục mà bạn không biết sẽ có bao nhiêu (ví dụ: một loạt mục dữ liệu) hoặc cho các nhóm tùy chọn/cài đặt liên quan (có thể là trong ví dụ Wordpress mà bạn đề cập đến?).

Nếu bạn tiếp tục với cách tiếp cận hàng loạt cho các đối số mảng thì ít nhất bạn nên biết tác động của nó đối với khả năng đọc và thực hiện một số bước để chống lại vấn đề đó.

+0

Tôi nghĩ tài liệu phù hợp có thể là một bước "rất hợp lệ để chống lại vấn đề đó". – ethanpil

+0

Tôi nghe những gì bạn đang nói, nhưng nếu mã của bạn được viết tốt, nó chủ yếu là tự ghi lại tài liệu, trong trường hợp đó bạn không cần phải 'tài liệu' nó (ví dụ: với nhận xét, v.v.). Điều này cũng giải quyết các vấn đề có thể xén khi mã không đồng bộ với 'tài liệu'. – Squig

4

Đường viền này trên Cargo Cult programming. Bạn nói điều này dễ đọc hơn và tự ghi lại. Tôi sẽ hỏi như thế nào? Để biết cách sử dụng hàm/phương thức của bạn, tôi phải đọc chính mã đó. Không đời nào tôi có thể biết cách sử dụng nó từ chữ ký. Nếu bạn sử dụng bất kỳ IDE hoặc trình soạn thảo nào có hỗ trợ gợi ý chữ ký phương thức thì đây sẽ là một PITA thực. Ngoài ra, bạn sẽ không thể sử dụng cú pháp kiểu gợi ý của PHP.

Nếu bạn thấy bạn đang mã hóa một tải các thông số, đặc biệt là các tham số tùy chọn thì nó cho thấy có thể có điều gì đó sai với thiết kế của bạn. Hãy xem xét cách khác bạn có thể đi về nó. Nếu một số hoặc tất cả các tham số có liên quan thì có thể chúng thuộc về lớp riêng của chúng.

4

Sử dụng array_merge() hoạt động tốt, nhưng sử dụng toán tử + cũng có thể được sử dụng; nó hoạt động theo cách khác, nó chỉ thêm các giá trị mặc định mà chưa có giá trị nào được đưa ra.

function useless_func(array $params = array()) 
{ 
    $params += array(
     'text' => 'default text', 
     'text2' => 'default text2', 
     'text3' => 'default text3', 
    ); 
} 

Xem thêm: Function Passing array to defined key

Một số điều bạn không nhận được với việc sử dụng các mảng như các đối số hàm được:

  1. kiểm tra kiểu (chỉ áp dụng đối với các đối tượng và mảng, nhưng nó có thể hữu ích và trong một số trường hợp dự kiến).
  2. trình chỉnh sửa văn bản thông minh (er) có tính năng thông tin chi tiết về mã sẽ hiển thị đối số mà hàm hiểu; sử dụng mảng mất đi tính năng đó, mặc dù bạn có thể thêm các khóa có thể có trong hàm docblock.
  3. do # 2 nó thực sự trở nên dễ bị lỗi hơn, bởi vì bạn có thể nhập sai phím mảng.
0

@ Mike, bạn cũng có thể "giải nén()" Lập luận của bạn $ params vào các biến địa phương, như thế này:

// Class will tokenize a string based on params 
public static function tokenize(array $params) 
{ 
    extract($params); 
    // Validate required elements 
    if (!isset($value)) { 
     throw new Exception(sprintf('Invalid $value: %s', serialize($params))); 
    } 

    // Localize optional elements 
    $value   = isset($value) ? $value : ''; 
    $separator  = isset($separator) ? $separator] : '-'; 
    $urlEncode  = isset($urlEncode) ? $urlEncode : false; 
    $allowedChars = isset($allowedChars) ? $allowedChars : array(); 
    $charsToRemove = isset($charsToRemove) ? $charsToRemove : array(); 

....

Cùng thực hiện, nhưng ngắn hơn.

0

Tôi đã sử dụng các mảng để thay thế một danh sách dài các tham số trong nhiều trường hợp và nó đã hoạt động tốt.Tôi đồng ý với những người trong bài đăng này đã đề cập về các trình chỉnh sửa mã không thể cung cấp gợi ý cho các đối số. Vấn đề là nếu tôi có 10 đối số, và 9 đầu tiên là trống/null nó chỉ trở nên khó sử dụng khi gọi hàm đó.

Tôi cũng muốn nghe cách thiết kế lại chức năng đòi hỏi nhiều đối số. Ví dụ, khi chúng ta có một hàm xây dựng câu lệnh SQL dựa trên lập luận chắc chắn được thiết lập:

function ($a1, $a2, ... $a10){ 

     if($a1 == "Y"){$clause_1 = " something = ".$a1." AND ";} 
     ... 
     if($a10 == "Y"){$clause_10 = " something_else = ".$a10." AND ";} 

     $sql = " 
     SELECT * FROM some_table 
     WHERE 
     ".$clause_1." 
     .... 
     ".$clause_10." 
     some_column = 'N' 
     "; 

     return $sql; 
    } 

Tôi muốn nhìn thấy PHP Entertain thêm một hàm helper bản địa mà có thể được sử dụng trong vòng một chức năng được gọi mà có thể hỗ trợ truyền một mảng các tham số bằng cách thực hiện kiểm tra kiểu cần thiết. PHP nhận ra điều này đến một mức độ nhất định bằng cách tạo hàm func_get_args() cho phép các đối số được truyền theo bất kỳ thứ tự nào. NHƯNG điều này sẽ chỉ vượt qua một COPY của các giá trị, vì vậy nếu bạn muốn truyền các đối tượng cho hàm này thì đây sẽ là một vấn đề. Nếu một hàm như vậy tồn tại, thì các trình soạn thảo mã sẽ có thể chọn nó và cung cấp chi tiết về các đối số có thể có.

+0

Nếu hàm có 10 đối số, có nhiều khả năng nó được thiết kế tồi và nên được suy nghĩ lại. –

11

Đừng làm vậy!

Việc chuyển tất cả trong một mảng là một ý tưởng tồi phần lớn thời gian.

  • Nó ngăn người dùng sử dụng chức năng của bạn mà không biết nó cần vận hành.
  • Nó cho phép bạn tạo ra các chức năng cần rất nhiều tham số khi lẽ bạn nên tạo một chức năng có nhu cầu lập luận chính xác hơn và một mục tiêu hẹp

Nó có vẻ như ngược lại của injecting trong một hàm những gì nó cần.

luận Chức năng có thể được cung cấp trong bất kỳ thứ tự

Tôi không có sở thích như vậy. Tôi không hiểu nhu cầu đó.

dễ dàng hơn để đọc mã/nhiều tự chủ tài liệu (theo ý kiến ​​của tôi)

Hầu hết các IDE sẽ giới thiệu bạn với những lập luận khác nhau một chức năng cần thiết. Nếu thấy một khai báo hàm như foo(Someclass $class, array $params, $id), nó rất rõ ràng chức năng cần. Tôi không đồng ý rằng một đối số param duy nhất dễ đọc hơn hoặc tự ghi lại tài liệu.

Ít dễ bị lỗi, vì khi gọi một hàm tôi phải điều tra các phím mảng phù

Cho phép mọi người vượt qua trong một mảng mà không biết rằng giá trị này sẽ được mặc định là không gần "không lỗi -dễ bị". Làm cho nó bắt buộc đối với mọi người để đọc chức năng của bạn trước khi sử dụng nó là một cách chắc chắn cho nó không bao giờ được sử dụng. Nói rằng cần ba đối số cùng với mặc định của chúng, số lỗi ít hơn vì mọi người gọi hàm của bạn sẽ biết giá trị nào sẽ được đặt mặc định và tin tưởng rằng nó sẽ hiển thị kết quả mong đợi.


Nếu vấn đề bạn đang cố giải quyết là số lượng đối số quá lớn, quyết định đúng là tái cấu trúc các chức năng của bạn thành các phần nhỏ hơn, không ẩn phụ thuộc hàm đằng sau mảng.

Các vấn đề liên quan