Каков правильный и самый простой способ сделать подготовленные операторы с PHP mysqli?

Я давно использую старый API mysql в PHP и хочу начать использовать mysqli как для скорости, так и для безопасности с новым проектом, над которым я работаю. Я просмотрел руководство и прочитал несколько руководств, но нашел много противоречивой и несколько запутанной информации о том, как выполнять подготовленные операторы в mysql.

Есть ли в этом коде что-то, чего там не должно быть, и есть ли что-то, чего не хватает? Кроме того, это самый простой способ сделать что-то простое вроде этого (кажется несколько сложным для такой простой задачи)?

Процедурный:

// build prepared statement
$query = mysqli_prepare($link, "SELECT email FROM users WHERE id = ?");

// bind parameters to statement
mysqli_stmt_bind_param($query, 's', $_GET['id']);

// execute statement
mysqli_stmt_execute($query);

// bind the variables to the result
mysqli_stmt_bind_result($query, $email);

// print the results
while (mysqli_stmt_fetch($query)) {
    echo $email;
}

// close the statement
mysqli_stmt_close($query);

// close connection
mysqli_close($link);

Объектно-ориентированный:

// build prepared statement
$query = $link->prepare("SELECT email FROM users WHERE id = ?");

// bind parameters to statement
$query->bind_param('s', $_GET['id']);

// execute statement
$query->execute();

// bind the variables to the result
$query->bind_result($email);

// print the results
while ($query->fetch()) {
    echo $email;
}

// close the statement
$query->close();

// close connection
$link->close();

person James Simpson    schedule 30.04.2011    source источник
comment
Я бы посоветовал пропустить MySQLi и сразу перейти к PDO. Класс PDOStatement имеет очень понятный и последовательный интерфейс.   -  person Phil    schedule 30.04.2011
comment
Вы должны были просто пропустить mysqli и сразу перейти к PDO. И почему вы настаиваете на использовании процедурного кода?!   -  person tereško    schedule 30.04.2011
comment
@ Фил, спасибо, я посмотрю на PDO.   -  person James Simpson    schedule 30.04.2011
comment
@teresko, я всегда занимался процедурами, поэтому я не знаю, будет ли хорошей идеей сразу перейти к ООП в этом проекте (из-за нехватки времени).   -  person James Simpson    schedule 30.04.2011
comment
О, только что заметил, что PDO - это просто OO, так что, может быть, мне стоит пойти дальше и сделать решительный шаг. Тем не менее, меня интересует мой первоначальный вопрос только с точки зрения обучения.   -  person James Simpson    schedule 30.04.2011


Ответы (1)


Вот внутренности почти не требующего пояснений класса, который инкапсулирует mysqli, включая подготовленные операторы, которые довольно сложны. Он довольно хорошо протестирован - я использую его уже год без изменений.

Он реализует только подготовленные операторы для выполнения команд SQL, потому что они изменяют данные и в противном случае часто требуют неприятных трюков с кодированием. Если вы хотите использовать SELECT, оставьте его в качестве упражнения для читателя — так проще. :)

<?php

class Db
{
    var $_mysqli;
    var $_result;
    var $_error_msg;

    public function __construct($server, $user, $password, $name)
    {
        $this->_mysqli = new mysqli("p:".$server, $user,
                                    $password, $name);
        if($this->_mysqli->connect_errno) 
        {
            $this->_error_msg = $this->_mysqli->connect_error;
        }
    }

    public function __destruct()
    {
    }

    private function sql_select($sql)
    {
        $this->_mysqli->query("SET NAMES 'utf8'"); // a little help for UTF8 io
        $this->_result = $this->_mysqli->query($sql);
    }

    private function sql_close()
    {
        $this->_mysqli->close();
    }


    public function ErrorMessage()
    {
        return $this->_error_msg;
    }

    public function SqlRows($sql)
    {
        $rows = array();
        $result = $this->sql_select($sql);
        if($this->IsError())
        {
            return $rows;
        }
        while($row = $result->fetch_array()) 
        {
            $rows[] = $row;
        }
        $result->free();
        return $rows;
    }

    public function SqlObjects($sql)
    {
        $objects = array();
        $result = $this->sql_select($sql);
        while($object = $this->_result->fetch_object()) 
        {
            $objects[] = $object;
        }
        $result->free();
        return $objects;
    }

    public function SqlOneObject($sql)
    {

        $result = $this->sql_select($sql);
        $obj = $result->fetch_object();
        $result->free();
        return $obj;
    }

    public function SqlOneRow($sql)
    {
        $result = $this->sql_select($sql);
        if(! is_object($result))
            return null;
        if($result->num_rows > 0)
            $row = $result->fetch_array();
        else
            $row = null;
        $result->free();
        return $row;
    }

    public function SqlOneValue($sql)
    {
        $result = $this->sql_select($sql);
        if(!empty($result))
        {
            $row = $result->fetch_array();
        }
        $result->free();
        return empty($row) ? null : $row[0] ;
    }

    // returns number of affected rows
    public function SqlExecute($sql)
    {
        $this->_result = $this->_mysqli->query($sql);
        return $this->affected_rows();
    }

    private function affected_rows()
    {
        return $this->_mysqli->affected_rows;
    }

    private function IsError()
    {
        if(empty($this->_mysqli))
            return false;
        return !empty($this->_mysqli->error);
    }

    // arguments are sql and an array of 
    // argument references (not values).
    public function SqlExecutePS($sql, $args)
    {
        $stmt = $this->_mysqli->prepare($sql);

        // make the type-string
        $typestr = make_typestring($args);
        $params = array($typestr);
        $params = array_merge($params, $args);

        call_user_func_array(array($stmt, 'bind_param'), $params);
        $stmt->execute();

        $ret = $this->affected_rows();
        $stmt->close();
        return $ret;
    }

    public function SqlExists($sql)
    {
        $result = $this->SqlOneRow($sql);
        return !empty($result[0]);
    }


    function make_typestring($args)
    {
        assert(is_array($args));
        $ret = "";
        foreach($args as $arg)
        {
            switch(gettype($arg))
            {
                case "boolean":
                case "integer":
                    $ret .= "i";
                    break;
                case "double":
                    $ret .= "d";
                    break;
                case "string":
                    $ret .= "s";
                    break;
                case "array":
                case "object":
                case "resource":
                case "NULL":
                default:
                    // call it a blob and hope
                    // you know what you're doing.
                    $ret .= "b";
                    break;
            }
        }
        return $ret;
    }
} 

?>
person dkretz    schedule 30.04.2011