2009-03-25 26 views
19

thông số chức năng được đặt tên có thể được mô phỏng trong PHP nếu tôi viết các chức năng như thế nàyMô phỏng các tham số hàm được đặt tên trong PHP, ý tưởng tốt hay xấu?

function pythonic(array $kwargs) 
{ 
    extract($kwargs); 
    // .. rest of the function body 
} 

// if params are optional or default values are required 
function pythonic(array $kwargs = array('name'=>'Jon skeet')) 
{ 
    extract($kwargs); 
    // .. rest of the function body 
} 

Ngoài mất IntelliSense trong IDE những nhược điểm có thể khác của phương pháp này là gì?

Edit:

An ninh: nên không an toàn là một vấn đề không trong trường hợp này, như các biến chiết xuất được giới hạn cho hoạt động phạm vi?

Trả lời

33

Tôi khuyên bạn nên sử dụng mảng kết hợp để chuyển các tham số có tên, nhưng giữ chúng trong mảng mà không cần giải nén chúng.

function myFunc(array $args) { 
    echo "Hi, " . $args['name']; 
    // etc 
} 

Có một vài lý do cho việc này. Nhìn vào hàm đó, bạn có thể thấy rõ ràng rằng tôi đang đề cập đến một trong các đối số được truyền vào hàm. Nếu bạn trích xuất chúng, và không nhận thấy extract() bạn (hoặc anh chàng tiếp theo) sẽ có gãi đầu của bạn tự hỏi, nơi này "$name" biến đến từ. Ngay cả khi bạn làm biết bạn đang trích xuất đối số cho biến cục bộ, đó vẫn là trò chơi đoán đến một mức độ nhất định.

Thứ hai, nó đảm bảo rằng mã khác không ghi đè các arg. Bạn có thể đã viết hàm của bạn chỉ mong muốn có đối số có tên là $foo$bar, do đó, trong mã khác của bạn, bạn xác định $baz = 8;, chẳng hạn. Sau đó, bạn có thể muốn mở rộng chức năng của mình để lấy thông số mới có tên "baz" nhưng quên thay đổi các biến khác của bạn, vì vậy bất kể thông tin nào được chuyển trong đối số, $baz sẽ luôn được đặt thành 8.

Có là một số lợi ích cho sử dụng mảng quá (những áp dụng chung cho các phương pháp chiết xuất hoặc để lại trong mảng): bạn có thể thiết lập một biến ở phía trên cùng của mỗi chức năng gọi $defaults:

function myFunc (array $args) { 
    $default = array(
     "name" => "John Doe", 
     "age" => "30" 
    ); 
    // overwrite all the defaults with the arguments 
    $args = array_merge($defaults, $args); 
    // you *could* extract($args) here if you want 

    echo "Name: " . $args['name'] . ", Age: " . $args['age']; 
} 

myFunc(array("age" => 25)); // "Name: John Doe, Age: 25" 

bạn thậm chí có thể loại bỏ tất cả các mục từ $args không có giá trị $default tương ứng. Bằng cách này bạn biết chính xác biến nào bạn có.

+2

Cách xử lý tốt nhất. Tôi rất tiếc khi không đọc câu trả lời của bạn trước khi viết. – Rolf

6

Theo kinh nghiệm của tôi, cách tiếp cận này thực sự là chỉ có lợi nếu một trong hai điều là đúng

  1. Đối với bất cứ lý do tiết giảm nhẹ, chữ ký lập luận của bạn là lớn. Tôi đã đi 6 tối đa - không vì bất kỳ lý do cụ thể nào mặc dù có vẻ đúng - nhưng tôi tự do thừa nhận rằng con số này là tùy ý.
  2. Tất cả hoặc nhiều đối số của bạn là tùy chọn và đôi khi bạn chỉ cần đặt giá trị cho giá trị thứ 5 hoặc một số điều như vậy. Thật khó chịu khi viết someFunc(null, null, null, null, 1);

Nếu một trong hai điều này đúng với bạn, hãy giả mạo các tham số được đặt tên với một mảng liên kết có thể là việc triển khai đúng. Ngoài việc biết khi nào nên tránh trích xuất (hoặc tránh hoàn toàn) Tôi không thể nghĩ ngay đến những nhược điểm khác.

Điều đó đang được nói, đôi khi cả hai vấn đề này đều có thể được giải quyết thông qua việc tái cấu trúc.

8

Dưới đây là một cách khác bạn có thể thực hiện việc này.

/** 
* Constructor. 
* 
* @named string 'algorithm' 
* @named string 'mode' 
* @named string 'key' 
*/ 
public function __construct(array $parameter = array()) 
{ 
    $algorithm = 'tripledes'; 
    $mode = 'ecb'; 
    $key = null; 
    extract($parameter, EXTR_IF_EXISTS); 
    //... 
} 

Với điều này thiết lập, bạn sẽ có được params mặc định, bạn không bị mất IntelliSense trong IDE và EXTR_IF_EXISTS làm cho nó an toàn bằng cách chỉ trích phím mảng được đã tồn tại như các biến.

(Bằng cách này, việc tạo ra các giá trị mặc định từ ví dụ mà bạn cung cấp là không tốt, bởi vì nếu một mảng của param được cung cấp mà không cần chỉ số một 'tên', giá trị mặc định của bạn bị mất.)

+0

Thao tác này có hoạt động cho các hàm không phải là phương thức lớp không? (trên giá trị mặc định: Tôi cũng nhận được rằng sau khi đăng câu hỏi) – Imran

+0

Chắc chắn, đây chỉ là một đoạn của một lớp học của tôi. Nó hoạt động cho bất cứ điều gì. – Mario

+1

Bạn có thể giải thích cách tạo công việc intellisense với thẻ '@ named' không? Tôi đang sử dụng PHPStorm, có intellisense tuyệt vời, nhưng tôi không thể làm cho nó nhận ra một thẻ '@ named'. Tôi không nghĩ đó là một thẻ bình luận PHP "thực", phải không? Nó không nằm trong danh sách [thẻ PHPDoc] (http://www.phpdoc.org/docs/latest/index.html) – Rich

2

Theo kinh nghiệm của tôi , nhược điểm của phương thức này là viết mã nhiều hơn. xem xét một cái gì đó như thế này:

function someFunc($requiredArg, $arg1 = "default11", $arg2 = "default2") { 

Để mô phỏng hành vi này khi đi qua tất cả mọi thứ trong một mảng bạn sẽ cần phải viết mã hơn, và "chức năng chữ ký" sẽ ít "rõ ràng và hiển nhiên".

function someFunc($requiredArg, $optionalArgs) { 
    // see other answers for good ways to simulate "named parameters" here 

Tôi tự hỏi liệu PHP có nên giải quyết vấn đề này trong tương lai hay không, có thể có cú pháp Pascal hoặc VB cho đối số chức năng.

Dù sao, tôi chỉ chuyển các tham số trong một mảng khi thực sự cần - giống như các hàm có bộ tham số có khả năng thay đổi rất nhiều trong quá trình phát triển. Các hàm này thường có nhiều tham số.

1

Những người khác đã giải đáp các điểm khác của bạn, tôi chỉ muốn nhận xét về khía cạnh bảo mật.

Bảo mật: Không an toàn không phải là vấn đề trong trường hợp này, vì các biến được trích xuất được giới hạn trong phạm vi chức năng?

Có và không. Mã bạn đã viết có thể (phụ thuộc vào việc bạn luôn khởi tạo các biến của mình sau cuộc gọi này) sẽ ghi đè lên các vars của bạn. Ví dụ:

function pythonic(array $kwargs = array('name'=>'Jon skeet')) 
{ 
    $is_admin = check_if_is_admin(); // initialize some variable... 

    extract($kwargs); 

    // Q: what is the value of $is_admin now? 
    // A: Depends on how this function was called... 
    // hint: pythonic([ 'is_admin' => true ]) 
} 

Điều gì làm cho mã này "loại-of-an toàn" là You Are the One ai đang gọi nó - vì vậy người dùng không thể cung cấp các thông số tùy ý (trừ khi bạn chuyển hướng POST vars có, tất nhiên;).

Theo quy tắc chung, bạn nên tránh phép thuật như vậy. Dòng với extract() có thể có các tác dụng phụ không mong muốn, do đó bạn không nên sử dụng nó. Trên thực tế, tôi không thể nghĩ đến việc sử dụng hợp pháp hàm extract() trong bất kỳ ứng dụng nào (tôi không nghĩ mình đã từng sử dụng nó).

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