2011-12-19 38 views
16

Tôi có một vài phương thức "setter" trên các lớp, và để thuận tiện, tôi đã thêm tham số tùy chọn $previous, tham số này bằng tham chiếu và điền nó với giá trị hiện tại trước khi thay thế bằng một. Ví dụ:Kiểm tra các đối số tùy chọn trong PHP

public function set_value($key, $value, &$previous = null) 
{ 
    $previous = $this->get_value($key); 
    $this->_values[$key] = $value; 
    return $this; 
} 

Điều này làm việc tốt; tuy nhiên trong một số trường hợp, phương pháp "getter" tương ứng là một quá trình bit chuyên sâu, và chạy nó vô điều kiện là một sự lãng phí. I figured tôi có thể kiểm tra:

if(null !== $previous) 
{ 
    $previous = $this->get_value($key); 
} 

này không hoạt động, mặc dù thường xuyên biến thông qua như là đối số cho $previous chưa được xác định trước đó trong đó là phạm vi và giá trị mặc định null anyway. Giải pháp duy nhất tôi đã bị hack ra là:

public function set_value($key, $value, &$previous = null) 
{ 
    $args = func_get_args(); 
    if(isset($args[2]) 
    { 
     $previous = $this->get_value($key); 
    } 
    $this->_values[$key] = $value; 
    return $this; 
} 

Hoặc, để một dòng nó:

if(array_key_exists(2, func_get_args())) 
{ 
    // ... 
} 

tôi không thích cơ thể phương pháp là dựa vào các chỉ số tham số (khi nó có vẻ là không cần thiết) Có cách nào sạch hơn để đạt được những gì tôi đang ở đây không?


Tôi đã thử:

if(isset($previous)){} 

if(!empty($previous)){} 

if(null !== $previous){} 

Không làm việc.

giải pháp có thể như vậy, cho đến nay:

if(func_num_args() == $num_params){} 

if(array_key_exists($param_index, func_get_args())){} 

// 5.4 
if(isset(func_get_args()[$param_index])){} 

// 5.4 
if(func_num_args() == (new \ReflectionMethod(__CLASS__, __FUNCTION__)) 
    ->getNumberOfParameters()){} 

@DaveRandom - Vì vậy, một cái gì đó trong lĩnh vực:

define('_NOPARAM', '_NOPARAM' . hash('sha4096', microtime())); 

function foo($bar = _NOPARAM) 
{ 
    // ... 
} 

@hoppa - Sử dụng trường hợp:

$obj->set_something('some_key', $some_value, $previous) // set 
    ->do_something_that_uses_some_key() 
    ->set_something('some_key', $previous) // and reset 
    ->do_something_that_uses_some_key() 
    -> ... 

Thay vì:

$previous = $obj->get_something('some_key'); // get 
$obj->set_something('some_key', $some_value) // set 
    ->do_something_that_uses_some_key(); 
    ->set_something($previous) // and reset 
    ->do_something_that_uses_some_key(); 
    -> ... 
+3

Could not bạn xác định các giá trị mặc định cho '$ previous' như' FALSE' (hoặc một số giá trị của " sai "loại" - sau đó bạn biết rằng nó là 'null' nó đã được thông qua, nhưng nó là' FALSE' (hoặc bất cứ điều gì) nó không phải là. Phương pháp này có lỗ hổng trong nó (người dùng có thể vượt qua giá trị mặc định của bạn) nhưng tôi nghĩ nó sẽ là một cách tiếp cận tốt - đặc biệt nếu bạn đặt giá trị mặc định là một chuỗi ngẫu nhiên dài. . – DaveRandom

+0

@DaveRandom - Giá trị trước đó có thể là boolean 'false' trong một số trường hợp. Tôi đã chọn 'null' cho mục đích ngữ nghĩa của nó," không có giá trị ". – Dan

+0

Xem nhận xét đã chỉnh sửa về chuỗi ngẫu nhiên dài - Tôi thừa nhận đó không phải là cách tiếp cận đẹp hay hoàn hảo, nhưng đó là phương pháp 99.99999% hoạt động ... – DaveRandom

Trả lời

3

có thể không phải là cách bạn muốn giải quyết vấn đề của bạn (kiểm tra lập luận bằng cách nào đó không bắt buộc), nhưng đây là cách tôi sẽ thực hiện nó:

public function set_value($key, $value) 
{ 
    $this->_values[$key] = $value; 
    return $this; 
} 
public function set_get_value($key, $value, &$previous) 
{ 
    $previous = $this->get_value($key); 
    $this->_values[$key] = $value; 
    return $this; 
} 

Sử dụng trường hợp ví dụ:

$obj->set_get_something('some_key', $some_value, $previous) // set AND get 
    ->do_something_that_uses_some_key() 
    ->set_something('some_key', $previous) // and reset 
    ->do_something_that_uses_some_key() 
    -> ... 

Tại sao lại sử dụng một chức năng khác?

Giải pháp này có một vài ưu điểm:

  1. tên là rõ ràng hơn, ít nhầm lẫn cho lập trình khác
  2. không tác dụng phụ tiềm ẩn
  3. giải quyết vấn đề của bạn với (không xác định) các biến đã có một giá trị
  4. không có phí gọi điện thoại func_num_args hoặc một số chức năng "meta" khác

EDIT: typo trong mã.

EDIT 2: lấy giá trị mặc định của & $ set_get_value trước() chức năng (nhờ draevor)

+0

Cách thay thế tốt. Chỉnh sửa nhỏ - '& $ trước' không cần có giá trị mặc định trong hàm thứ hai, nó có nghĩa là ở đó. – deviousdodo

+0

thực sự :) đã chỉnh sửa! – catchmeifyoutry

1

Trích từ các ý kiến ​​/ thảo luận ở trên:

Để kiểm tra xem đối số được thông qua bạn có 2 lựa chọn - kiểm tra giá trị của lập luận chống lại một giá trị (như bạn đã thực hiện với null) hoặc kiểm tra số lượng đối số.

Nếu bạn đi với tùy chọn đầu tiên, không có giá trị nào không thể truyền từ bên ngoài hàm, do đó sẽ luôn có cơ hội cho các mặt tích cực sai (cùng một điều đang xảy ra với null). Ví dụ của DaveRandom với một chuỗi ngẫu nhiên là đủ cho hầu hết các trường hợp, nhưng tôi thấy nó là quá mức cần thiết.

Tôi nghĩ tùy chọn thứ hai là tùy chọn sạch nhất (nhanh, dễ đọc, v.v.). Như một cải tiến nhỏ so với những gì bạn đã thực hiện với func_get_args, tôi muốn sử dụng func_num_args - theo cách này bạn sẽ kiểm tra số lượng đối số đã qua, không phải chỉ số đối số.

+0

Cảm ơn @draevor - Kiểm tra chỉnh sửa của tôi trong "* Tôi đã thử/Giải pháp có thể *", cái cuối cùng (* một lần 5,4 lượt truy cập trên đường phố *) sẽ hoạt động tốt cho khả năng sử dụng lại tính khả thi của lớp học. Tham số $ previous' luôn luôn là cuối cùng. Như tôi đã nói trước đây, câu trả lời của bạn chắc chắn là ứng cử viên tốt nhất, tôi sẽ để điều này một chút, và đánh dấu của bạn nếu không có gì khác đi ra ngoài đồ gỗ. – Dan

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