2010-04-10 12 views
12

Supponendo che sia possibile, come si passerebbero gli argomenti facendo riferimento a una funzione variadica senza generare un avviso in PHP? Non possiamo più usare l'operatore '&' in una chiamata di funzione, altrimenti lo accetterei (anche se sarebbe soggetto a errori, se un programmatore lo dimentica).Come possono essere passati argomenti in variabili alle funzioni variadiche in PHP?

Ciò che ha ispirato sono le vecchie classi wrapper MySQLi che ho scoperto (in questi giorni, userei solo PDO). L'unica differenza tra i wrapper e le classi MySQLi è che i wrapper generano eccezioni piuttosto che restituire 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 difficoltà sta nel chiamare metodi come bind_result nel wrapper. È possibile definire in modo esplicito le funzioni di aritmetica costante (ad esempio bind_param), consentendo il passaggio per riferimento. bind_result, tuttavia, tutti gli argomenti devono essere pass-by-reference. Se si chiama bind_result su un'istanza di MySQLi_stmt_throwing così com'è, gli argomenti vengono passati per valore e l'associazione non verrà eseguita.

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

Poiché le classi di cui sopra non sono più in uso, questa domanda è solo una questione di curiosità. Approcci alternativi alle classi wrapper non sono rilevanti. La definizione di un metodo con un gruppo di argomenti che richiede valori predefiniti Null non è corretta (cosa succede se si definiscono 20 argomenti, ma la funzione viene chiamata con 21?). Le risposte non hanno nemmeno bisogno di essere scritte in termini di MySQL_stmt_throwing; esiste semplicemente per fornire un esempio concreto.

+0

Ops ... appena trovato la domanda che questo dups: http://stackoverflow.com/questions/1925253/php-variable-length-argument-list-by-reference , anche se preferisco la risposta di magro sotto alla risposta accettata per l'altra domanda. – outis

risposta

6

Non esiste un modo per passare elenchi di argomenti di lunghezza variabile per riferimento in PHP. È una limitazione fondamentale della lingua.

V'è, tuttavia, una soluzione con array(&$var1, &$var2...) sintassi:

<?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 potrebbe anche essere dichiarato function test($args) ma volevo illustrare che questo funziona con la func_get_args() famiglia di funzioni. È lo array(&$x) che fa passare la variabile per riferimento, non per la firma della funzione.

Da un commento sulla documentazione di PHP su argomenti delle funzioni: http://php.net/manual/en/functions.arguments.php

+0

Chiamami pazzo, ma intendevi per il tuo metodo 'test' essere' pow2' o viceversa? –

+0

@anthony Il primo, grazie. – meagar

+0

@meager, non è un problema, è tardi qui era solo curioso di aver iniziato ad avere allucinazioni. –

8

Dal PHP 5.6 si può pass arguments by reference a una funzione variadic. Ecco un esempio da the RFC:

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