How can arguments to variadic functions be passed by reference in PHP?
Posted
by outis
on Stack Overflow
See other posts from Stack Overflow
or by outis
Published on 2010-04-10T03:11:10Z
Indexed on
2010/04/10
3:13 UTC
Read the original article
Hit count: 448
Assuming it's possible, how would one pass arguments by reference to a variadic function without generating a warning in PHP? We can no longer use the '&' operator in a function call, otherwise I'd accept that (even though it would be error prone, should a coder forget it).
What inspired this is are old MySQLi wrapper classes that I unearthed (these days, I'd just use PDO). The only difference between the wrappers and the MySQLi classes is the wrappers throw exceptions rather than returning 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;
}
}
The difficulty lies in calling methods such as bind_result
on the wrapper. Constant-arity functions (e.g. bind_param
) can be explicitly defined, allowing for pass-by-reference. bind_result
, however, needs all arguments to be pass-by-reference. If you call bind_result
on an instance of MySQLi_stmt_throwing
as-is, the arguments are passed by value and the binding won't take.
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) {
...
}
Since the above classes are no longer in use, this question is merely a matter of curiosity. Alternate approaches to the wrapper classes are not relevant. Defining a method with a bunch of arguments taking Null
default values is not correct (what if you define 20 arguments, but the function is called with 21?). Answers don't even need to be written in terms of MySQL_stmt_throwing
; it exists simply to provide a concrete example.
© Stack Overflow or respective owner