如何在PHP中动态绑定mysqli bind_param参数?

如何在PHP中动态绑定mysqli bind_param参数?,php,arrays,mysqli,bind,prepared-statement,Php,Arrays,Mysqli,Bind,Prepared Statement,我一直在学习在sql查询中使用准备好的和绑定的语句,到目前为止,我已经想到了这一点,它工作正常,但当涉及到多个参数或不需要参数时,它根本不是动态的 public function get_result($sql,$parameter) { # create a prepared statement $stmt = $this->mysqli->prepare($sql); # bind parameters for markers

我一直在学习在sql查询中使用准备好的和绑定的语句,到目前为止,我已经想到了这一点,它工作正常,但当涉及到多个参数或不需要参数时,它根本不是动态的

public function get_result($sql,$parameter)
    {
        # create a prepared statement
    $stmt = $this->mysqli->prepare($sql);

        # bind parameters for markers
    # but this is not dynamic enough...
        $stmt->bind_param("s", $parameter);

        # execute query 
        $stmt->execute();

    # these lines of code below return one dimentional array, similar to mysqli::fetch_assoc()
        $meta = $stmt->result_metadata(); 

        while ($field = $meta->fetch_field()) { 
            $var = $field->name; 
            $$var = null; 
            $parameters[$field->name] = &$$var; 
        }

        call_user_func_array(array($stmt, 'bind_result'), $parameters); 

        while($stmt->fetch()) 
        { 
            return $parameters;
            //print_r($parameters);      
        }


        # close statement
        $stmt->close();
    }
这就是我如何调用对象类

$mysqli = new database(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$output = new search($mysqli);
有时我不需要传入任何参数

$sql = "
SELECT *
FROM root_contacts_cfm
";

print_r($output->get_result($sql));
$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'1'));
$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
AND root_contacts_cfm.cnt_firstname = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'1','Tk'));
有时候我只需要一个参数

$sql = "
SELECT *
FROM root_contacts_cfm
";

print_r($output->get_result($sql));
$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'1'));
$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
AND root_contacts_cfm.cnt_firstname = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'1','Tk'));
有时我只需要一个以上的参数

$sql = "
SELECT *
FROM root_contacts_cfm
";

print_r($output->get_result($sql));
$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'1'));
$sql = "
SELECT *
FROM root_contacts_cfm
WHERE root_contacts_cfm.cnt_id = ?
AND root_contacts_cfm.cnt_firstname = ?
ORDER BY cnt_id DESC
";

print_r($output->get_result($sql,'1','Tk'));
因此,我认为这条线不够动态,无法完成上述动态任务

$stmt->bind_param("s", $parameter);
为了动态构建一个bind_参数,我在网上的其他帖子中发现了这个

call_user_func_array(array(&$stmt, 'bind_params'), $array_of_params);
我试着修改了一些代码,但是我一无所获

if (strnatcmp(phpversion(),'5.3') >= 0) //Reference is required for PHP 5.3+ 
    { 
        $refs = array(); 
        foreach($arr as $key => $value) 
            $array_of_param[$key] = &$arr[$key]; 

       call_user_func_array(array(&$stmt, 'bind_params'), $array_of_params);

     }
为什么??你知道我该怎么做吗

或者有更好的解决方案

或者也许有更好的解决方案

这个答案对你并没有多大帮助,但是你应该认真考虑从MySqLi切换到./P> 这主要是因为PDO使用内置函数完成了您在mysqli中尝试执行的操作。除了具有,还可以采用参数数组

PDO很容易扩展,添加方便的方法来获取所有内容并返回,而不是进行准备-执行舞蹈非常容易

或者也许有更好的解决方案

这个答案对你并没有多大帮助,但是你应该认真考虑从MySqLi切换到./P> 这主要是因为PDO使用内置函数完成了您在mysqli中尝试执行的操作。除了具有,还可以采用参数数组


PDO很容易扩展,添加方便的方法来获取所有内容并返回,而不是执行“准备-执行”舞蹈非常容易。

找到了mysqli的答案:

public function get_result($sql,$types = null,$params = null)
    {
        # create a prepared statement
        $stmt = $this->mysqli->prepare($sql);

        # bind parameters for markers
        # but this is not dynamic enough...
        //$stmt->bind_param("s", $parameter);

        if($types&&$params)
        {
            $bind_names[] = $types;
            for ($i=0; $i<count($params);$i++) 
            {
                $bind_name = 'bind' . $i;
                $$bind_name = $params[$i];
                $bind_names[] = &$$bind_name;
            }
            $return = call_user_func_array(array($stmt,'bind_param'),$bind_names);
        }

        # execute query 
        $stmt->execute();

        # these lines of code below return one dimentional array, similar to mysqli::fetch_assoc()
        $meta = $stmt->result_metadata(); 

        while ($field = $meta->fetch_field()) { 
            $var = $field->name; 
            $$var = null; 
            $parameters[$field->name] = &$$var; 
        }

        call_user_func_array(array($stmt, 'bind_result'), $parameters); 

        while($stmt->fetch()) 
        { 
            return $parameters;
            //print_r($parameters);      
        }


        # the commented lines below will return values but not arrays
        # bind result variables
        //$stmt->bind_result($id); 

        # fetch value
        //$stmt->fetch(); 

        # return the value
        //return $id; 

        # close statement
        $stmt->close();
    }

说到这一点,mysqli真是太差劲了。我想我应该迁移到PDO

找到了mysqli的答案:

public function get_result($sql,$types = null,$params = null)
    {
        # create a prepared statement
        $stmt = $this->mysqli->prepare($sql);

        # bind parameters for markers
        # but this is not dynamic enough...
        //$stmt->bind_param("s", $parameter);

        if($types&&$params)
        {
            $bind_names[] = $types;
            for ($i=0; $i<count($params);$i++) 
            {
                $bind_name = 'bind' . $i;
                $$bind_name = $params[$i];
                $bind_names[] = &$$bind_name;
            }
            $return = call_user_func_array(array($stmt,'bind_param'),$bind_names);
        }

        # execute query 
        $stmt->execute();

        # these lines of code below return one dimentional array, similar to mysqli::fetch_assoc()
        $meta = $stmt->result_metadata(); 

        while ($field = $meta->fetch_field()) { 
            $var = $field->name; 
            $$var = null; 
            $parameters[$field->name] = &$$var; 
        }

        call_user_func_array(array($stmt, 'bind_result'), $parameters); 

        while($stmt->fetch()) 
        { 
            return $parameters;
            //print_r($parameters);      
        }


        # the commented lines below will return values but not arrays
        # bind result variables
        //$stmt->bind_result($id); 

        # fetch value
        //$stmt->fetch(); 

        # return the value
        //return $id; 

        # close statement
        $stmt->close();
    }

说到这一点,mysqli真是太差劲了。我想我应该迁移到PDO

使用PHP5.6,您可以借助(
..$var
)和

例如:

$mysqli = new database(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$output = new search($mysqli);


$sql = "SELECT * FROM root_contacts_cfm WHERE root_contacts_cfm.cnt_id = ?
        AND root_contacts_cfm.cnt_firstname = ?
        ORDER BY cnt_id DESC";

$res = $output->get_result($sql, 'ss',array('1','Tk'));
while($row = res->fetch_assoc()){
   echo $row['fieldName'] .'<br>';
}
$mysqli=新数据库(数据库主机、数据库用户、数据库通行证、数据库名称);
$output=新搜索($mysqli);
$sql=“从root\u contacts\u cfm中选择*,其中root\u contacts\u cfm.cnt\u id=?
和root_contacts_cfm.cnt_firstname=?
按cnt_id DESC订购”;
$res=$output->get_result($sql,'ss',array('1','Tk');
而($row=res->fetch_assoc()){
echo$row['fieldName']。
; }
使用PHP5.6,您可以在(
..$var
的帮助下轻松完成这项工作,并使用

例如:

$mysqli = new database(DB_HOST,DB_USER,DB_PASS,DB_NAME);
$output = new search($mysqli);


$sql = "SELECT * FROM root_contacts_cfm WHERE root_contacts_cfm.cnt_id = ?
        AND root_contacts_cfm.cnt_firstname = ?
        ORDER BY cnt_id DESC";

$res = $output->get_result($sql, 'ss',array('1','Tk'));
while($row = res->fetch_assoc()){
   echo $row['fieldName'] .'<br>';
}
$mysqli=新数据库(数据库主机、数据库用户、数据库通行证、数据库名称);
$output=新搜索($mysqli);
$sql=“从root\u contacts\u cfm中选择*,其中root\u contacts\u cfm.cnt\u id=?
和root_contacts_cfm.cnt_firstname=?
按cnt_id DESC订购”;
$res=$output->get_result($sql,'ss',array('1','Tk');
而($row=res->fetch_assoc()){
echo$row['fieldName']。
; }
使用PHP 5.6或更高版本

$stmt->bind_param(str_repeat("s", count($data)), ...$data);
使用PHP5.5或更低版本,您可能(我也确实)希望以下功能能够正常工作:

call_user_func_array(
    array($stmt, "bind_param"),
    array_merge(array(str_repeat("s", count($data))), $data));
…但是
mysqli_stmt::bind_param
希望它的参数是引用,而这会传递一个值列表

您可以通过首先创建对原始数组的引用数组来解决这个问题(尽管这是一个难看的解决方法)

$references_to_data = array();
foreach ($data as &$reference) { $references_to_data[] = &$reference; }
unset($reference);
call_user_func_array(
    array($stmt, "bind_param"),
    array_merge(array(str_repeat("s", count($data))), $references_to_data));

使用PHP 5.6或更高版本

$stmt->bind_param(str_repeat("s", count($data)), ...$data);
使用PHP5.5或更低版本,您可能(我也确实)希望以下功能能够正常工作:

call_user_func_array(
    array($stmt, "bind_param"),
    array_merge(array(str_repeat("s", count($data))), $data));
…但是
mysqli_stmt::bind_param
希望它的参数是引用,而这会传递一个值列表

您可以通过首先创建对原始数组的引用数组来解决这个问题(尽管这是一个难看的解决方法)

$references_to_data = array();
foreach ($data as &$reference) { $references_to_data[] = &$reference; }
unset($reference);
call_user_func_array(
    array($stmt, "bind_param"),
    array_merge(array(str_repeat("s", count($data))), $references_to_data));

我通过应用类似于PDO的系统解决了这个问题。SQL占位符是以双点字符开头的字符串。例:

:id, :name, or :last_name
然后,您可以直接在占位符字符串中指定数据类型,方法是在双精度点之后添加规范字母,并在助记符变量之前添加下划线字符。例:

:i_id (i=integer), :s_name or :s_last_name (s=string)
如果没有添加类型字符,那么函数将通过分析保存数据的php变量来确定数据的类型。例:

$id = 1 // interpreted as an integer
$name = "John" // interpreted as a string
该函数返回一个类型数组和一个值数组,您可以使用该数组在循环中执行php函数mysqli_stmt_bind_param()

$sql = 'SELECT * FROM table WHERE code = :code AND (type = :i_type OR color = ":s_color")';
$data = array(':code' => 1, ':i_type' => 12, ':s_color' => 'blue');

$pattern = '|(:[a-zA-Z0-9_\-]+)|';
if (preg_match_all($pattern, $sql, $matches)) {
    $arr = $matches[1];
    foreach ($arr as $word) {
        if (strlen($word) > 2 && $word[2] == '_') {
            $bindType[] = $word[1];
        } else {
            switch (gettype($data[$word])) {
                case 'NULL':
                case 'string':
                    $bindType[] = 's';
                    break;
                case 'boolean':
                case 'integer':
                    $bindType[] = 'i';
                    break;
                case 'double':
                    $bindType[] = 'd';
                    break;
                case 'blob':
                    $bindType[] = 'b';
                    break;
                default:
                    $bindType[] = 's';
                    break;
            }
        }    
        $bindValue[] = $data[$word];
    }    
    $sql = preg_replace($pattern, '?', $sql);
}

echo $sql.'<br>';
print_r($bindType);
echo '<br>';
print_r($bindValue);
$sql='从表中选择*,其中code=:code和(type=:i_type或color=“:s_color”);
$data=数组(“:code'=>1':i_type'=>12':s_color'=>blue”);
$pattern='|(:[a-zA-Z0-9_ \-]+)|';
if(preg_match_all($pattern,$sql,$matches)){
$arr=$matches[1];
foreach($arr作为$word){
如果(strlen($word)>2&&$word[2]==''''''\u'){
$bindType[]=$word[1];
}否则{
开关(gettype($data[$word])){
大小写“NULL”:
大小写“string”:
$bindType[]='s';
打破
“布尔”大小写:
“整数”情况:
$bindType[]=“i”;
打破
双格:
$bindType[]='d';
打破
案例“blob”:
$bindType[]=“b”;
打破
违约:
$bindType[]='s';
打破
}
}    
$bindValue[]=$data[$word];
}    
$sql=preg_replace($pattern,“?”,$sql);
}
回显$sql。“
”; 打印($bindType); 回声“
”; 打印(bindValue);
我通过应用类似于PDO的系统解决了这个问题。SQL占位符是以双点字符开头的字符串。例:

:id, :name, or :last_name
然后,您可以直接在占位符字符串中指定数据类型,方法是在dou之后立即添加规范字母