2010-04-10 72 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; 
}