Оболочка PHP mysqli: передача по ссылке с помощью __call () и call_user_func_array () - PullRequest
2 голосов
/ 02 апреля 2010

Я давний поклонник stackoverflow, первый постер. Я хотел бы посмотреть, может ли кто-нибудь помочь мне с этим. Позвольте мне покопаться с небольшим кодом, и я объясню свою проблему. У меня есть следующие классы оболочки:

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
}

Моя проблема в том, что когда я вызываю bind_result() в классе mysqli_stmt_wrapper, мои переменные не передаются по ссылке и ничего не возвращается. Для иллюстрации, если я запускаю этот раздел кода, я получаю только NULL:

$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();

Я также получаю приятную ошибку от PHP, которая говорит мне: PHP Warning: Parameter 1 to mysqli_stmt::bind_result() expected to be a reference, value given in test.php on line 48


Я пытался перегрузить функцию bind_param(), но не могу понять, как получить переменное число аргументов по ссылке. func_get_args(), похоже, тоже не может помочь.

Если я передам переменные по ссылке, как в $stmt->bind_result(&$cfg_key, &$cfg_value), это должно сработать, но это устаревшее поведение и выдает больше ошибок.

У кого-нибудь есть идеи по этому поводу? Большое спасибо за ваше время.

Ответы [ 3 ]

2 голосов
/ 02 апреля 2010

Если вы выйдете из класса mysqli_stmt, вы обойдете справочную проблему. (у которого нет чистого раствора)

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);
  }
}
1 голос
/ 26 августа 2010

С небольшой помощью ребят из канала #php irc я нашел следующее решение:

// 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);
}
0 голосов
/ 02 апреля 2010

Я предполагаю, что это потому, что оригинальная сигнатура функции указывает, что она ожидает ссылки, тогда как ваш __call не может этого сделать. Поэтому попробуйте не использовать __call, а явно добавить bind_result с той же сигнатурой функции, что и в оригинале.

...