出现在mysqli的代码和call_user_func_array错误()(Errors appea

2019-07-18 19:02发布

试图建立一个动态的,其中使用mysqli的条款时,我得到了不少错误:

警告:参数2 mysqli_stmt :: bind_param()预计为参考,值...给出线319

警告:mysqli_stmt ::执行():(HY000 / 2031):在没有准备好的声明中...为参数提供在线328数据

警告:mysqli_stmt :: bind_result():(HY000 / 2031):在没有准备好的声明中...为参数提供在线331数据

警告:mysqli_stmt :: store_result():(HY000 / 2014):命令不同步; 你现在不能在...上线332运行此命令

即时猜测有是需要解决的问题,但发生的事情是,如果这两个中的一个下拉菜单的不等于变化不大All或者如果双方不等于All ,然后将其与错误的出现。

下面是代码显示两个下拉菜单和所述查询(具有动态where子句)随后根据选择N个选项:

HTML:

学生下拉菜单:

<select name="student" id="studentsDrop">
<option value="All">All</option>
<option value="11">John May</option>
<option value="23">Chris Park</option>
</select>

问题编号下拉菜单

<select name="question" id="questionsDrop">
<option value="All">All</option>
<option value="123">1</option>
<option value="124">2</option>
<option value="125">3</option>
</select>

PHP /库MySQLi:

      function StudentAnswers()
        {


    /*BELOW IS THE QUERY WHERE I AM TRYING TO RETRIEVE DATA DEPENDING ON THE ASSESSMENT CHOSEN AND
    THEN DEPENDING ON OPTIONS CHOSEN IN STUDENT AND QUESTION NUMBER DROP DOWN MENU */

        $selectedstudentanswerqry = "
        SELECT
        StudentAlias, StudentForename, StudentSurname, q.SessionId, QuestionNo, QuestionContent, o.OptionType, q.NoofAnswers, GROUP_CONCAT( DISTINCT Answer
        ORDER BY Answer SEPARATOR ',' ) AS Answer, r.ReplyType, QuestionMarks, 
        GROUP_CONCAT(DISTINCT StudentAnswer ORDER BY StudentAnswer SEPARATOR ',') AS StudentAnswer, ResponseTime, MouseClick, StudentMark
        FROM Student s
        INNER JOIN Student_Answer sa ON (s.StudentId = sa.StudentId)
        INNER JOIN Student_Response sr ON (sa.StudentId = sr.StudentId)
        INNER JOIN Question q ON (sa.QuestionId = q.QuestionId)
        INNER JOIN Answer an ON q.QuestionId = an.QuestionId
        LEFT JOIN Reply r ON q.ReplyId = r.ReplyId
        LEFT JOIN Option_Table o ON q.OptionId = o.OptionId
        ";

        // Initially empty
        $where = array('q.SessionId = ?');
        $parameters = array($_POST["session"]);
        $parameterTypes = 'i';

        // Check whether a specific student was selected
        if($_POST["student"] !== 'All') {
            $where[] = 'sa.StudentId = ?';
            $parameters[] =& $_POST["student"];
            $parameterTypes .= 'i';
        }

        // Check whether a specific question was selected
        // NB: This is not an else if!
        if($_POST["question"] !== 'All') {
            $where[] = 'q.QuestionId = ?';
            $parameters[] =& $_POST["question"];
            $parameterTypes .= 'i';
        }

        // If we added to $where in any of the conditionals, we need a WHERE clause in
        // our query
        if(!empty($where)) {
            $selectedstudentanswerqry .= ' WHERE ' . implode(' AND ', $where);
            global $mysqli;
            $selectedstudentanswerstmt=$mysqli->prepare($selectedstudentanswerqry);
            // You only need to call bind_param once
                call_user_func_array(array($selectedstudentanswerstmt, 'bind_param'),
                array_merge(array($parameterTypes), $parameters)); //LINE 319 ERROR 1
        }

    //Add group by and order by clause to query
        $selectedstudentanswerqry .= "
          GROUP BY sa.StudentId, q.QuestionId
          ORDER BY StudentAlias, q.SessionId, QuestionNo
        ";

        // get result and assign variables (prefix with db)
        $selectedstudentanswerstmt->execute(); //LINE 328 ERROR 2

    //bind database fields 
$selectedstudentanswerstmt->bind_result($detailsStudentAlias,$detailsStudentForename,$detailsStudentSurname,$detailsSessionId,$detailsQuestionNo, 
        $detailsQuestonContent,$detailsOptionType,$detailsNoofAnswers,$detailsAnswer,$detailsReplyType,$detailsQuestionMarks,$detailsStudentAnswer,$detailsResponseTime,
        $detailsMouseClick,$detailsStudentMark); //LINE 331 ERROR 3

    //store results retrieved
        $selectedstudentanswerstmt->store_result(); //LINE 332 ERROR 4

    //count number of rows retrieved
        $selectedstudentanswernum = $selectedstudentanswerstmt->num_rows();     

    //output query
        echo "$selectedstudentanswerqry";

        }

        ?>

这里是一个演示: DEMO

在演示中选择从下拉菜单并提交评估。 你会看到两个下拉菜单。 让他们都设置为All并提交,它将输出查询,没有任何问题。 没有在下拉菜单中的一个,改变All到一个特定的学生或问题,然后提交。 现在你会看到错误

如何转储:

所述的结果var_dump(array_merge(array($parameterTypes), $parameters))); 当我和值选择会话(评估) 31 ,学号值40 ,和题号值81 ,和WHERE子句WHERE q.SessionId = ? AND sa.StudentId = ? AND q.QuestionId = ? WHERE q.SessionId = ? AND sa.StudentId = ? AND q.QuestionId = ?

我正在此输出: array(4) { [0]=> string(3) "iii" [1]=> string(2) "31" [2]=> string(2) "40" [3]=> string(2) "81" }

Answer 1:

这是由不断变化造成了棘手的情况call_user_func_array在PHP 5.4的行为(我必须假设): 文档

由于丑陋,因为这是,它会工作调用bind_param这种方式:

$selectedstudentanswerqry .= ' WHERE ' . implode(' AND ', $where);
global $mysqli;
$stmt =$mysqli->prepare($selectedstudentanswerqry);

if (count($where) === 1) {
    $stmt->bind_param($parameterTypes, $parameters[0]);
}
else if (count($where) === 2) {
    $stmt->bind_param($parameterTypes, $parameters[0], $parameters[1]);
}
else if (count($where) === 3) {
    $stmt->bind_param($parameterTypes, $parameters[0], $parameters[1],
       $parameters[2]);
}

我恨这个就像你可能会做。 我建议从切换mysqliPDO它处理变量参数在一个更漂亮的方式(并具有出众的语法一般,在我看来):

$pdo = new PDO('mysql:host=localhost', 'username', 'password');
$stmt = $pdo->prepare($selectedstudentanswerqry);
$stmt->execute($parameters);
$selectedstudentanswernum = $stmt->rowCount();


Answer 2:

警告:参数2 mysqli_stmt :: bind_param()预计为参考,值...给出线319

这应该是不言自明的:bind_param的参数是通过引用传递,因此必须为变量。 你可能会忽略的是, array_merge返回一个新的数组,不包含原始变量只是值引用。

下面的错误是因为参数没有绑定只是后来到这一点。

一个可能的解决方案是保存在您的引用$parameters数组,这些甚至会被保存array_merge:

$parameters[] =& $_POST["student"];

$parameters[] =& $_POST["question"];

现在的数组项$parameters都是引用POST变量和数组项目array_merge结果也。

编辑:看起来这是不可能的了,看@Explosion丸



Answer 3:

这仍然是不足够的理由抛弃的mysqli为PDO,尤其是当我有很好的理由不使用PDO来代替,在那个时候。 在另一方面,是的,他们并不需要强制mysqli_stmt :: bind_param和bind_result方法需要传递的ByRef变量,他们可能有他们返回数组。 但是,真正的问题是,通话时传递的引用不再是可能的,但mysqli的还是需要通过按参考,所以谁在使用动态参数(任何人谁拥有直观的SQL即是)任何人被逮住了在这个问题上,包括我自己。 花几个小时编写转换阵列设置成动态准备SQL语句的自定义mysqli的包装类之后,我不是试图重写所有PDO工作,特别是因为PDO有要求命名参数作为绑定的一部分,我会写多种功能,以打造什么发送列表...每种类型的查询。 这是反直觉的,我不会浪费了无数的时间试图模仿我所用的mysqli完成。

在这一点上唯一的障碍是,我们无法通过变量call_user_func_array()按地址和mysqli_stmt :: bind_ *要求他们按地址传递......所以我们唯一的选择是:1)写一个新的call_user_func_array()其被设计为显式的bind_工作*方法,其中所述传递的参数基本上复制内到一个新的数组或通过args设置的变量,然后传递这些回调函数的ByRef; 或者2)重写的mysqli类做了正确的方式,只是看什么传递,执行SQL,然后返回结果如预期。 没有理由认为我们传递给方法来执行SQL必须以结果惨败,应该就像一个SQL控制台治疗处理。

因为我是从编码,直到我的眼睛几乎流血的方式太累,我要带我的保持停留在5.3.10-1 PHP版本,直到我真正得到固定问题的正确方法的不建议选择。 对于那些会说“对于所有这些努力,为什么不把钱花在写你的PDO的包装呢?” ......我的回答很简单:我使用PHP和MySQL专门在许多项目中的服务器是一个小小的电脑非常有限的房间和资源,更何况CPU的计算能力。 PDO加载一切可以做,你要使用不只是什么,所以也有在你的资源的东西,你甚至不会使用,这我的项目无法承受失去做了一些保留。

值得庆幸的是,保持我忍住PHP版本是不会在这个时候是有害的。 这是很多企业级的服务器群,以避免不得不“上的当前版本”的东西,这也是出奇的昂贵的升级一切每隔几年带都记录下来只是要怎么做。



文章来源: Errors appearing in mysqli code and call_user_func_array()