2010-04-02 4 views
2

Je suis un fan de stackoverflow depuis longtemps, affiche de première fois. J'aimerais voir si quelqu'un peut m'aider avec ça. Permettez-moi de creuser avec un petit code, puis je vais expliquer mon problème. Je les classes d'emballage suivantes:PHP mysqli wrapper: passage par référence avec __call() et call_user_func_array()

class mysqli_wrapper 
{ 
    private static $mysqli_obj; 
    function __construct() // Recycles the mysqli object 
    { 
     if (!isset(self::$mysqli_obj)) 
     { 
      self::$mysqli_obj = new mysqli(MYSQL_SERVER, MYSQL_USER, MYSQL_PASS, MYSQL_DBNAME); 
     } 
    } 
    function __call($method, $args) 
    { 
     return call_user_func_array(array(self::$mysqli_obj, $method), $args); 
    } 
    function __get($para) 
    { 
     return self::$mysqli_obj->$para; 
    } 
    function prepare($query) // Overloaded, returns statement wrapper 
    { 
     return new mysqli_stmt_wrapper(self::$mysqli_obj, $query); 
    } 
} 

class mysqli_stmt_wrapper 
{ 
    private $stmt_obj; 
    function __construct($link, $query) 
    { 
     $this->stmt_obj = mysqli_prepare($link, $query); 
    } 
    function __call($method, $args) 
    { 
     return call_user_func_array(array($this->stmt_obj, $method), $args); 
    } 
    function __get($para) 
    { 
     return $this->stmt_obj->$para; 
    } 
    // Other methods will be added here 
} 

Mon problème est que quand je l'appelle bind_result() la classe mysqli_stmt_wrapper, mes variables ne semblent pas être passé par référence et rien est renvoyée. Pour illustrer, si je lance cette section de code, je ne reçois NULL de:

$mysqli = new mysqli_wrapper; 

$stmt = $mysqli->prepare("SELECT cfg_key, cfg_value FROM config"); 
$stmt->execute(); 
$stmt->bind_result($cfg_key, $cfg_value); 

while ($stmt->fetch()) 
{ 
    var_dump($cfg_key); 
    var_dump($cfg_value); 
} 
$stmt->close(); 

Je reçois aussi une erreur agréable de PHP qui me dit: PHP Warning: Parameter 1 to mysqli_stmt::bind_result() expected to be a reference, value given in test.php on line 48


J'ai essayé de surcharger le bind_param() fonction, mais je ne peux pas comprendre comment obtenir un nombre variable d'arguments par référence. func_get_args() ne semble pas être en mesure d'aider non plus.

Si je passe les variables par référence comme dans $stmt->bind_result(&$cfg_key, &$cfg_value) cela devrait fonctionner, mais c'est un comportement obsolète et jette plus d'erreurs.

Est-ce que quelqu'un a des idées à ce sujet? Merci beaucoup pour votre temps.

+0

Pourquoi la nécessité d'une classe d'emballage et non choisir d'étendre directement la classe mysqli? On dirait que tu te fais du mal avec toi-même? 'class my_db extends mysqli {}' – ChrisR

+0

La raison pour laquelle je ne veux pas étendre la classe 'mysqli', c'est parce que je devrais appeler' parent :: __ construct() 'et ensuite je ne pourrais pas recycler l'unique objet 'mysqli'. Ce à quoi je ne pensais pas, cependant, était d'étendre l'objet 'mysqli_stmt' que je reçois de la méthode' prepare'. Merci quand même pour l'entrée. – Dave

Répondre

2

Si vous étendez à partir de la classe mysqli_stmt, vous éviterez le problème de référence. (Qui n'a pas de solution propre)

class mysqli_stmt_wrapper extends mysqli_stmt { 
    public function __construct($link, $query) { 
    parent::__construct($link, $query); 
    } 
} 

class mysqli_wrapper extends mysqli { 
    public function prepare($query) { 
    return new mysqli_stmt_wrapper($this, $query); 
    } 
} 
+0

Salut bob. Merci, c'est parfait! Je n'avais pas réalisé que vous pouviez simplement construire un nouvel objet 'mysqli_stmt' comme ça. Je pensais que d'autres 'trucs magiques' se produisaient dans la méthode originale 'mysqli-> prepare', donc je devrais appeler le parent pour préparer mon objet. Merci encore. stackoverflow FTW – Dave

0

Je suppose que c'est parce que la signature de la fonction d'origine spécifie qu'elle attend des références, alors que votre __call ne peut pas le faire. Par conséquent, essayez de ne pas utiliser __call mais en ajoutant explicitement le bind_result avec la même signature de fonction que l'original.

+0

Oui, c'est pourquoi je dis, j'ai essayé de surcharger 'bind_result', mais le problème est que la fonction' bind_result' peut accepter n'importe quel nombre d'arguments, et il faut que chacun soit passé par référence. 'func_get_args()' ne semble pas faire ça pour moi. – Dave

+0

Oh, n'est-ce pas? Pardon! Je pense que vous êtes un peu lié, ici. Badum! (Et désolé encore, pour cela.) – janmoesen

1

Avec un peu d'aide des gars du canal irC#php je suis venu avec la solution suivante:

// We have to explicitly declare all parameters as references, otherwise it does not seem possible to pass them on without 
// losing the reference property. 
public function bind_result (&$v1 = null, &$v2 = null, &$v3 = null, &$v4 = null, &$v5 = null, &$v6 = null, &$v7 = null, &$v8 = null, &$v9 = null, &$v10 = null, &$v11 = null, &$v12 = null, &$v13 = null, &$v14 = null, &$v15 = null, &$v16 = null, &$v17 = null, &$v18 = null, &$v19 = null, &$v20 = null, &$v21 = null, &$v22 = null, &$v23 = null, &$v24 = null, &$v25 = null, &$v26 = null, &$v27 = null, &$v28 = null, &$v29 = null, &$v30 = null, &$v31 = null, &$v32 = null, &$v33 = null, &$v34 = null, &$v35 = null) { 
    // debug_backtrace returns arguments by reference, see comments at http://php.net/manual/de/function.func-get-args.php 
    $trace = debug_backtrace(); 
    $args = &$trace[0]['args']; 
    return call_user_func_array(array($this->mysqlObj, 'bind_result'), $args); 
}