2010-04-10 34 views
12

Giả sử có thể, làm cách nào để chuyển đối số bằng cách tham chiếu đến hàm variadic mà không tạo cảnh báo trong PHP? Chúng tôi không còn có thể sử dụng toán tử '&' trong một cuộc gọi hàm nữa, nếu không tôi sẽ chấp nhận điều đó (mặc dù nó sẽ dễ xảy ra lỗi, nếu một người lập trình quên nó).Làm thế nào các đối số cho các hàm variadic được chuyển qua tham chiếu trong PHP?

Điều gì đã truyền cảm hứng cho đây là các lớp trình bao bọc MySQLi cũ mà tôi đã khai quật (những ngày này, tôi chỉ sử dụng PDO). Sự khác biệt duy nhất giữa các trình bao bọc và các lớp MySQLi là các trình bao bọc ném các ngoại lệ thay vì trả về FALSE.

class DBException extends RuntimeException {} 
... 
class MySQLi_throwing extends mysqli { 
    ... 
    function prepare($query) { 
     $stmt = parent::prepare($query); 
     if (!$stmt) { 
      throw new DBException($this->error, $this->errno); 
     } 
     return new MySQLi_stmt_throwing($this, $query, $stmt); 
    } 
} 
// I don't remember why I switched from extension to composition, but 
// it shouldn't matter for this question. 
class MySQLi_stmt_throwing /* extends MySQLi_stmt */ { 
    protected $_link, $_query, $_delegate; 

    public function __construct($link, $query, $prepared) { 
     //parent::__construct($link, $query); 
     $this->_link = $link; 
     $this->_query = $query; 
     $this->_delegate = $prepared; 
    } 
    function bind_param($name, &$var) { 
     return $this->_delegate->bind_param($name, $var); 
    } 
    function __call($name, $args) { 
     //$rslt = call_user_func_array(array($this, 'parent::' . $name), $args); 
     $rslt = call_user_func_array(array($this->_delegate, $name), $args); 
     if (False === $rslt) { 
      throw new DBException($this->_link->error, $this->errno); 
     } 
     return $rslt; 
    } 
} 

Khó khăn nằm trong các phương thức gọi như bind_result trên trình bao bọc. Các hàm liên tục (ví dụ: bind_param) có thể được xác định rõ ràng, cho phép tham chiếu chéo. Tuy nhiên, bind_result cần tất cả đối số để được tham chiếu. Nếu bạn gọi bind_result trên một thể hiện của MySQLi_stmt_throwing như là, các đối số được truyền theo giá trị và ràng buộc sẽ không mất.

try { 
    $id = Null; 
    $stmt = $db->prepare('SELECT id FROM tbl WHERE ...'); 
    $stmt->execute() 
    $stmt->bind_result($id); 
    // $id is still null at this point 
    ... 
} catch (DBException $exc) { 
    ... 
} 

Vì các lớp trên không còn được sử dụng, câu hỏi này chỉ là vấn đề tò mò. Các cách tiếp cận thay thế cho các lớp trình bao bọc không có liên quan. Định nghĩa một phương thức với một bó các đối số tham gia Null giá trị mặc định là không đúng (nếu bạn xác định 20 đối số, nhưng hàm được gọi với 21?). Câu trả lời thậm chí không cần phải được viết theo điều khoản của MySQL_stmt_throwing; nó tồn tại đơn giản để cung cấp một ví dụ cụ thể.

+0

Whoops ... chỉ cần tìm thấy câu hỏi rằng điều này một dups: http://stackoverflow.com/questions/1925253/php-variable-length-argument-list-by-reference , mặc dù tôi thích câu trả lời ít ỏi hơn bên dưới cho câu trả lời được chấp nhận cho câu hỏi khác. – outis

Trả lời

6

Không có cách nào để chuyển danh sách đối số độ dài biến bằng cách tham chiếu trong PHP. Đó là một hạn chế cơ bản của ngôn ngữ.

Có, tuy nhiên, một cách giải quyết với array(&$var1, &$var2...) cú pháp:

<?php 

/** raise all our arguments to the power of 2 */ 
function pow2() { 
     $args = &func_get_arg(0); 

     for ($i = 0; $i< count($args); ++$i) { 
      $args[$i] *= 2; 
     } 
} 


$x = 1; $y = 2; $z = 3; 
pow2(array(&$x, &$y, &$z)); // this is the important line 

echo "$x, $y, $z"; // output "2, 4, 6" 

?> 

Test cũng có thể được khai báo function test($args) nhưng tôi muốn để minh họa điều này làm việc với gia đình func_get_args() chức năng. Nó là array(&$x) làm cho biến được truyền qua tham chiếu, chứ không phải chữ ký hàm.

Từ một bình luận về tài liệu PHP về đối số chức năng: http://php.net/manual/en/functions.arguments.php

+0

Gọi tôi là điên, nhưng ý bạn là phương pháp 'test' là 'pow2' hay ngược lại? –

+0

@anthony Trước đây, cảm ơn bạn. – meagar

+0

@meager, Không sao đâu, đã muộn ở đây chỉ là tò mò nếu tôi bắt đầu ảo giác. –

8

Tính đến PHP 5.6 bạn có thể pass arguments by reference đến một chức năng variadic. Dưới đây là một ví dụ từ the RFC:

public function prepare($query, &...$params) { 
    $stmt = $this->pdo->prepare($query); 
    foreach ($params as $i => &$param) { 
     $stmt->bindParam($i + 1, $param); 
    } 
    return $stmt; 
} 
Các vấn đề liên quan