mysqli绑定方法和call_user_func_array

时间:2012-11-01 00:53:20

标签: php mysql variables bind

我有以下代码:

    function insertrow($tablename,$record){
        $columns = $this->gettablecol($tablename);
        $types = $this->getbindtypestring($columns);    
        array_unshift($record, $types);                                             
        if(count($columns) && $types){              
            $query = 'INSERT INTO '.$tablename.' VALUES (?'.str_repeat(',?',count($columns)-1).')';
            if($stm = $this->linkid->prepare($query)){                  
                $res = call_user_func_array(array(&$stm,"bind_param"), $params);                    
                $stm->execute();                    
                print_r($stm);
                $stm->close();                                      
            }
        }
    }

$ record数组如下所示:

    (
        [0] => sssisssssssssssi
        [recordid] => TEST1
        [recdate] => 2012-10-31 08:45:49
        [lastmod] => 2012-10-31 08:45:49
        [delflag] => 0
        [cusname] => Dilbert
        [address1] => 181 Somewhere
        [address2] => 
        [city] => St. Petersburg
        [state] => FL
        [zipcode] => 33713
        [telephone] => 8135551212
        [faxnumber] => 8135551313
        [webaddress] => 
        [taxid] => 260708780
        [pinnumber] => 12345
        [isactive] => 0 
)

但$ stm告诉我没有数据:

mysqli_stmt Object
(
    [affected_rows] => 0
    [insert_id] => 0
    [num_rows] => 0
    [param_count] => 16
    [field_count] => 0
    [errno] => 2031
    [error] => No data supplied for parameters in prepared statement
    [sqlstate] => HY000
    [id] => 1
)

似乎$ record数组以某种方式格式错误。任何见解都将不胜感激。


比尔,比尔,谢谢你的单挑。我接受了你的建议并将API转换为PDO ....我必须承认我喜欢与它合作更容易;但是,我的问题还没有解决。我将insertrow方法更改为:

    function insertrow($tablename,$record){         
        $this->connect();
        $columns = $this->gettablecol($tablename);      
        if(count($columns)){                
            $query = 'INSERT INTO '.$tablename.' VALUES (?'.str_repeat(',?',count($columns)-1).')';
            try{
                $stm = $this->linkid->prepare($query);                  
                $stm->execute($record);
            }catch(PDOException $e){
                $this->errormsg = $e.getMessage();
                $this.errhandler();
                exit();
            }           
        }
    }

记录如下:

Array
(
    [recordid] => TEST1
    [recdate] => 2012-11-01 09:12:50
    [lastmod] => 2012-11-01 09:12:50
    [delflag] => 0
    [cusname] => Dilbert
    [address1] => 181 Somewhere
    [address2] => 
    [city] => St. Petersburg
    [state] => FL
    [zipcode] => 33713
    [telephone] => 8135551212
    [faxnumber] => 8135551313
    [webaddress] => 
    [taxid] => 260708780
    [pinnumber] => 12345
    [isactive] => 0
)

我甚至将$ record的值复制到一个新数组中:

$newrec = array();
foreach($record as $row){
   $newrec = $row;
}

看起来像这样:

 Array
(
    [0] => TEST1
    [1] => 2012-11-01 09:01:32
    [2] => 2012-11-01 09:01:32
    [3] => 0
    [4] => Dilbert
    [5] => 181 Somewhere
    [6] => 
    [7] => St. Petersburg
    [8] => FL
    [9] => 33713
    [10] => 8135551212
    [11] => 8135551313
    [12] => 
    [13] => 260708780
    [14] => 12345
    [15] => 0
)

并将其传递给$ stm->执行($ newrec),但它不起作用并且没有异常。还有什么我能看的吗?

此时我已经删除了传递$ record数组并刚刚对值进行了硬编码:

$stm->execute(array('TEST2','2012-10-10 00:00:00','2012-10-10 00:00:00',0,'1','2','3','4','5','6','7','8','9','0','11',0));

即使准备和执行都恢复正常,我仍然没有将记录插入表中。

我是否有必要将参数绑定到特定的数据类型?

1 个答案:

答案 0 :(得分:2)

使用bind_param的难度是我在开发可重用数据库访问层时不喜欢使用Mysqli的原因。它可以完成,但PHP的引用使它不必要地神秘。

有关解决方案,请参阅mysqli_prepare vs PDO

中的答案

基本上,您传递的数组必须是引用数组,而不是标量数组。

我发现在开发DBAL时使用PDO要容易得多。你不必绑定任何东西。您只需将数组传递给PDOStatement::execute()


重新编辑:

我是PDO对你有帮助。但这可能不是原始问题的根本原因。如果我的建议是一场疯狂的追逐,我会道歉。但至少现在你正在使用PDO,所以这是一种角色建设体验。 : - )

我在代码中注意到的两件事,但我不确定这些是否是问题:

您根据$ columns数组的数量添加了许多参数占位符,但是您如何知道这与$ record数组的计数相同?如果参数占位符的数量与您为execute()提供的值的数量不匹配,那么这是一个错误。

你应该检查:

if (count($columns) != count($record)) { 
  // report error
}

或者,您可以确保只在$ record数组中包含作为键提供的列:

$columns_to_insert = array_intersect($columns, array_keys($record));

顺便说一句(这不是一个错误,只是一个提示),我会生成这样的参数占位符序列,只是为了避免字符串连接和一个一个错误的风险:

join(",", array_fill(0, count($record), "?"))

我注意到的另一件事是你没有检查execute()的返回值。如果它返回false,那么就会出现错误,您应该investigate the nature of the error

您正在捕获异常,但PDO的默认模式是而不是以抛出异常,而只是设置函数的返回值以指示错误。您可以以这种方式使用它,否则您必须明确启用异常抛出模式:

$this->linkid->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

该设置在PDO连接期间是全局的;每次插入行时都不必这样做。