Suponiendo que sea posible, ¿cómo se pasarían argumentos por referencia a una función variadica sin generar una advertencia en PHP? Ya no podemos usar el operador '&' en una llamada a función, de lo contrario, aceptaría eso (aunque sería propenso a errores, un codificador debería olvidarlo).¿Cómo se pueden pasar argumentos a funciones variadic por referencia en PHP?
Lo que inspiró esto son las viejas clases de envoltorios de MySQL que encontré (en estos días, solo usaría PDO). La única diferencia entre los wrappers y las clases de MySQLi es que los wrappers lanzan excepciones en lugar de devolver 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;
}
}
La dificultad radica en llamar a métodos como bind_result
en el contenedor. Las funciones de constante constante (por ejemplo, bind_param
) se pueden definir explícitamente, lo que permite pasar de referencia. bind_result
, sin embargo, necesita que todos los argumentos pasen por referencia. Si llama al bind_result
en una instancia de MySQLi_stmt_throwing
tal como está, los argumentos se pasan por valor y el enlace no se realizará.
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) {
...
}
Dado que las clases anteriores ya no se utilizan, esta pregunta es simplemente una cuestión de curiosidad. Los enfoques alternativos a las clases contenedoras no son relevantes. Definir un método con un grupo de argumentos que toma Null
valores por defecto no es correcto (¿qué ocurre si define 20 argumentos, pero la función se llama con 21?). Las respuestas ni siquiera necesitan escribirse en términos de MySQL_stmt_throwing
; existe simplemente para proporcionar un ejemplo concreto.
chillidos ... acaba de encontrar la cuestión que éste dups: http://stackoverflow.com/questions/1925253/php-variable-length-argument-list-by-reference , aunque prefiero la respuesta de Meager a continuación a la respuesta aceptada para la otra pregunta. – outis