6

我正在尝试动态绑定 mysql_stmt 参数并在关联数组中获取结果。我在 stackoverflow 上找到了这篇文章,其中 Amber 使用以下代码发布了答案:

原帖: 如何使用准备好的语句制作正确的 mysqli 扩展类?

“假设您实际上想要编写自己的版本(而不是使用其他答案建议的现有库之一 - 这些也是不错的选择)......

这里有几个功能,您可能会发现它对检查很有用。第一个允许您将查询结果绑定到关联数组,第二个允许您传入两个数组,一个是有序的键数组,另一个是这些键的关联数据数组,并将该数据绑定到准备好的声明:”

function stmt_bind_assoc (&$stmt, &$out) {
    $data = mysqli_stmt_result_metadata($stmt);
    $fields = array();
    $out = array();

$fields[0] = $stmt;
$count = 1;

while($field = mysqli_fetch_field($data)) {
    $fields[$count] = &$out[$field->name];
    $count++;
}
call_user_func_array(mysqli_stmt_bind_result, $fields);

}

function stmt_bind_params($stmt, $fields, $data) {
    // Dynamically build up the arguments for bind_param
    $paramstr = '';
    $params = array();
    foreach($fields as $key)
    {
        if(is_float($data[$key]))
            $paramstr .= 'd';
        elseif(is_int($data[$key]))
            $paramstr .= 'i';
        else
            $paramstr .= 's';
        $params[] = $data[$key];
    }
    array_unshift($params, $stmt, $paramstr);
    // and then call bind_param with the proper arguments
    call_user_func_array('mysqli_stmt_bind_param', $params);
}

我尝试研究代码以了解它的作用,并且我已经使第二个功能正常工作,但我不知道应该做什么才能使用第一个功能。如何使用它来检索类似于 mysqli_result::fetch_assoc() 的数组?

我希望能够以您过去使用的方式利用结果:

while ($row = mysql_fetch_array($result)){
  echo $row['foo']." ".$row['bar'];
}

请帮助我在这方面取得一些进展:)

4

4 回答 4

13

好的,这是一种方法:

已编辑,以修复获取多行时的错误

$sql = "SELECT `first_name`,`last_name` FROM `users` WHERE `country` =? AND `state`=?";
$params = array('Australia','Victoria');

/*
    In my real app the below code is wrapped up in a class 
    But this is just for example's sake.
    You could easily throw it in a function or class
*/

// This will loop through params, and generate types. e.g. 'ss'
$types = '';                        
foreach($params as $param) {        
    if(is_int($param)) {
        $types .= 'i';              //integer
    } elseif (is_float($param)) {
        $types .= 'd';              //double
    } elseif (is_string($param)) {
        $types .= 's';              //string
    } else {
        $types .= 'b';              //blob and unknown
    }
}
array_unshift($params, $types);

// Start stmt
$query = $this->connection->stmt_init(); // $this->connection is the mysqli connection instance
if($query->prepare($sql)) {

    // Bind Params
    call_user_func_array(array($query,'bind_param'),$params);

    $query->execute(); 

    // Get metadata for field names
    $meta = $query->result_metadata();

    // initialise some empty arrays
    $fields = $results = array();

    // This is the tricky bit dynamically creating an array of variables to use
    // to bind the results
    while ($field = $meta->fetch_field()) { 
        $var = $field->name; 
        $$var = null; 
        $fields[$var] = &$$var; 
    }


    $fieldCount = count($fieldNames);

// Bind Results                                     
call_user_func_array(array($query,'bind_result'),$fields);

$i=0;
while ($query->fetch()){
    for($l=0;$l<$fieldCount;$l++) $results[$i][$fieldNames[$l]] = $fields[$fieldNames[$l]];
    $i++;
}

    $query->close();

    // And now we have a beautiful
    // array of results, just like
    //fetch_assoc
    echo "<pre>";
    print_r($results);
    echo "</pre>";
}
于 2011-06-05T07:06:43.967 回答
9

伊曼纽尔的答案工作正常,如果只选择一行!如果查询选择多行,则 $results-Array 为每一行保存一个结果,但结果始终填充最后一个条目。在 fetch() 中稍作改动——虽然它运行良好。

$sqlStmt 是一个字符串,用 mysql-query 填充

$params 是一个数组,里面填充了应该传递的变量

$results 是一个空数组,用于保存结果

    if (!is_string($sqlStmt) || empty($sqlStmt)) {
        return false;
    }

    // initialise some empty arrays
    $fields = array();
    $results = array();

    if ($stmt = $this->prepare($sqlStmt)) {
        // bind params if they are set
        if (!empty($params)) {
            $types = '';
            foreach($params as $param) {
                // set param type
                if (is_string($param)) {
                    $types .= 's';  // strings
                } else if (is_int($param)) {
                    $types .= 'i';  // integer
                } else if (is_float($param)) {
                    $types .= 'd';  // double
                } else {
                    $types .= 'b';  // default: blob and unknown types
                }
            }

            $bind_names[] = $types;
            for ($i=0; $i<count($params);$i++) {
                $bind_name = 'bind' . $i;       
                $$bind_name = $params[$i];      
                $bind_names[] = &$$bind_name;   
            }

            call_user_func_array(array($stmt,'bind_param'),$bind_names);
        }

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

        // Get metadata for field names
        $meta = $stmt->result_metadata();

        // This is the tricky bit dynamically creating an array of variables to use
        // to bind the results
        while ($field = $meta->fetch_field()) { 
            $var = $field->name; 
            $$var = null; 
            $fields[$var] = &$$var;
        }

        // Bind Results
        call_user_func_array(array($stmt,'bind_result'),$fields);

        // Fetch Results
        $i = 0;
        while ($stmt->fetch()) {
            $results[$i] = array();
            foreach($fields as $k => $v)
                $results[$i][$k] = $v;
            $i++;
        }

        // close statement
        $stmt->close();
    }
于 2012-01-16T15:45:06.403 回答
1

只是将@Emmanuel 和@matzino 的出色答案与选择PDO 而不是mysqli 时可以获得的代码进行比较:

$sql = "SELECT `first_name`,`last_name` FROM `users` WHERE `country` =? AND `state`=?";
$params = array('Australia','Victoria');

$stm = $query->prepare($sql);
$stm->execute($params); 
$results = $stm->fetchAll(); // or fetch() or fetchColumn() depends on expected type

哎呀,仅此而已?

于 2013-03-16T14:20:30.017 回答
1

使用上面的答案后,我发现自己需要进行一些清理,尤其是“fieldNames []”部分。下面的代码是程序风格的。我希望它对某人有用。

我从一个可以动态查询数据的类中删除了代码。为了便于阅读,我删除了一些内容。在我的课程中,我允许用户定义定义表和外键,以便限制前端的数据输入以及所述相关数据的过滤和排序选项。这些都是我删除的所有参数以及自动查询生成器。

$query = "SELECT `first_name`,`last_name` FROM `users` WHERE `country` =? AND `state`=?";
$params = array('Australia','Victoria');

////////////// GENERATE PARAMETER TYPES IF ANY //////////////
// This will loop through parameters, and generate types. ex: 'ss'
$types = '';
$params_size = sizeof($params);
if($params_size > 0)
{
    foreach($params as $param)
    {
        if(is_int($param))
        {
            $types .= 'i';              //integer
        }else if(is_float($param))
        {
            $types .= 'd';              //double
        }else if(is_string($param))
        {
            $types .= 's';              //string
        }else
        {
            $types .= 'b';              //blob and unknown
        }
    }
    array_unshift($params, $types);
}
////////////////////////////////////////////////////////////


// This is the tricky part to dynamically create an array of
// variables to use to bind the results

//below from http://php.net/manual/en/mysqli-result.fetch-field.php
/*
name        The name of the column
orgname     Original column name if an alias was specified
table       The name of the table this field belongs to (if not calculated)
orgtable    Original table name if an alias was specified
def         Reserved for default value, currently always ""
db          Database (since PHP 5.3.6)
catalog     The catalog name, always "def" (since PHP 5.3.6)
max_length  The maximum width of the field for the result set.
length      The width of the field, as specified in the table definition.
charsetnr   The character set number for the field.
flags       An integer representing the bit-flags for the field.
type        The data type used for this field
decimals    The number of decimals used (for integer fields)
*/

/// FIELD TYPE REFERENCE ///
/*
numerics
-------------
BIT: 16
TINYINT: 1
BOOL: 1
SMALLINT: 2
MEDIUMINT: 9
INTEGER: 3
BIGINT: 8
SERIAL: 8
FLOAT: 4
DOUBLE: 5
DECIMAL: 246
NUMERIC: 246
FIXED: 246

dates
------------
DATE: 10
DATETIME: 12
TIMESTAMP: 7
TIME: 11
YEAR: 13

strings & binary
------------
CHAR: 254
VARCHAR: 253
ENUM: 254
SET: 254
BINARY: 254
VARBINARY: 253
TINYBLOB: 252
BLOB: 252
MEDIUMBLOB: 252
TINYTEXT: 252
TEXT: 252
MEDIUMTEXT: 252
LONGTEXT: 252
*/

if($stmt = mysqli_prepare($db_link, $query))
{
    // BIND PARAMETERS IF ANY //
    if($params_size > 0)
    {
        call_user_func_array(array($stmt, 'bind_param'), makeValuesReferenced($params));
    }

    mysqli_stmt_execute($stmt);

    $meta = mysqli_stmt_result_metadata($stmt);


    $field_names = array();
    $field_length = array();
    $field_type = array();
    $output_data = array();

    /// THIS GET THE NAMES OF THE FIELDS AND ASSIGNS NEW VARIABLES USING THE FIELD NAME. THESE VARIABLES ARE THEN SET TO NULL ///
    $count = 0;
    while($field = mysqli_fetch_field($meta))
    {
        $field_names[$count] = $field->name;// field names
        $var = $field->name;
        $$var = null;
        $field_names_variables[$var] = &$$var;// fields variables using the field name
        $field_length[$var] = $field->length;// field length as defined in table
        $field_type[$var] = $field->type;// field data type as defined in table (numeric return)
        $count++;
    }
    setFieldLengthInfo($field_length);
    setFieldTypesInfo($field_type);

    $field_names_variables_size = sizeof($field_names_variables);
    call_user_func_array(array($stmt, 'bind_result'), $field_names_variables);

    $count = 0;
    while(mysqli_stmt_fetch($stmt))
    {
        for($l = 0; $l < $field_names_variables_size; $l++)
        {
            $output_data[$count][$field_names[$l]] = $field_names_variables[$field_names[$l]];/// THIS SETS ALL OF THE FINAL DATA USING THE DYNAMICALLY CREATED VARIABLES ABOVE
        }
        $count++;
    }
    mysqli_stmt_close($stmt);


    echo "<pre>";
    print_r($output_data);
    echo "</pre>";
}


function makeValuesReferenced($arr)
{
    $refs = array();
    foreach($arr as $key => $value)
        $refs[$key] = &$arr[$key];
    return $refs;
}
于 2017-02-12T00:48:49.007 回答