2010-04-10 152 views
12

假設可能,如何通過引用可變參數傳遞參數而不會在PHP中產生警告?我們不能再在函數調用中使用'&'操作符,否則我會接受(即使它容易出錯,應該由編碼器將其忽略)。如何通過參考在PHP中傳遞可變參數的參數?

是什麼啓發了這個是我發掘的舊MySQLi包裝類(這些日子裏,我只是使用PDO)。包裝和MySQLi類的唯一區別是包裝引發異常,而不是返回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; 
    } 
} 

難點在於調用包裝器上的方法,如bind_result。可以顯式定義常量函數(例如bind_param),允許通過引用。然而,bind_result需要所有參數傳遞參考。如果您按原樣對MySQLi_stmt_throwing的實例調用bind_result,則參數將按值傳遞,並且綁定不會執行。

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) { 
    ... 
} 

由於上述類不再使用,這個問題只是一個好奇心問題。對包裝類的替代方法是不相關的。定義一個採用Null默認值的參數簇的方法是不正確的(如果你定義了20個參數,但函數是用21調用的呢?)。答案甚至不需要寫成MySQL_stmt_throwing;它只是提供一個具體的例子。

+0

哎呦......剛剛發現的問題,這其中的DUP:http://stackoverflow.com/questions/1925253/php-variable-length-argument-list-by-reference儘管我更喜歡微薄的回答下面的答案接受另一個問題。 – outis 2010-04-10 22:13:07

回答

6

在PHP中沒有辦法通過引用來傳遞可變長度參數列表。這是該語言的一個基本限制。

有,然而,與array(&$var1, &$var2...)語法解決方法:

<?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也被宣佈爲function test($args),但我想說明的是這個作品與家庭func_get_args()的功能。它是array(&$x),它使變量通過引用傳遞,而不是函數簽名。

從對函數的參數在PHP的文檔註釋:http://php.net/manual/en/functions.arguments.php

+0

叫我瘋了,但是你的意思是你的'測試'方法是'pow2',反之亦然? – 2010-04-10 04:53:49

+0

@anthony前者,謝謝。 – meagar 2010-04-10 05:07:58

+0

@meager,不是問題,這裏遲到只是好奇,如果我開始產生幻覺。 – 2010-04-10 05:11:36

8

在PHP 5.6,你可以pass arguments by reference的一個可變參數函數。下面是the RFC一個例子:

public function prepare($query, &...$params) { 
    $stmt = $this->pdo->prepare($query); 
    foreach ($params as $i => &$param) { 
     $stmt->bindParam($i + 1, $param); 
    } 
    return $stmt; 
}