Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/89.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php mysqli代码和call_user_func_array()中出现错误_Php_Html_Mysql_Mysqli - Fatal编程技术网

Php mysqli代码和call_user_func_array()中出现错误

Php mysqli代码和call_user_func_array()中出现错误,php,html,mysql,mysqli,Php,Html,Mysql,Mysqli,在尝试使用mysqli创建动态where子句时,我遇到了不少错误: 警告:mysqli_stmt::bind_param()的参数2应为 参考,在…中给出的值。。。在线319 警告:mysqli_stmt::execute():(HY000/2031):未为提供任何数据 已准备语句中的参数。。。在线328 警告:mysqli_stmt::bind_result():(HY000/2031):未提供任何数据 对于。。。在线331 警告:mysqli_stmt::store_result():(HY

在尝试使用mysqli创建动态where子句时,我遇到了不少错误:

警告:mysqli_stmt::bind_param()的参数2应为 参考,在…中给出的值。。。在线319

警告:mysqli_stmt::execute():(HY000/2031):未为提供任何数据 已准备语句中的参数。。。在线328

警告:mysqli_stmt::bind_result():(HY000/2031):未提供任何数据 对于。。。在线331

警告:mysqli_stmt::store_result():(HY000/2014):命令超出 同步;您现在无法在中运行此命令。。。在线332

我猜解决这些问题需要做一些改变,但是如果两个下拉菜单中的一个不等于
All
,或者两者都不等于
All
,那么就会出现错误

下面是显示下拉菜单和查询(带有dynamic where子句)的代码,根据所选的n个选项显示:

HTML:

      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";

        }

        ?>
学生下拉菜单:

<select name="student" id="studentsDrop">
<option value="All">All</option>
<option value="11">John May</option>
<option value="23">Chris Park</option>
</select>
这里有一个演示:

在演示中,从下拉菜单中选择评估并提交。您将看到两个下拉菜单。将它们都设置为
All
并提交,它将毫无问题地输出查询。否在其中一个下拉菜单中,将
All
更改为特定学生或问题,然后提交。现在您将看到错误

VAR转储:

      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";

        }

        ?>
var_转储(array_merge(array($parameterTypes),$parameters))的结果当我选择值为
31
、学号值为
40
、题号值为
81
、WHERE子句为
WHERE q.SessionId=?和sa.StudentId=?q.QuestionId=?

我得到这个输出:
array(4){[0]=>string(3)“iii”[1]=>string(2)“31”[2]=>string(2)“40”[3]=>string(2)“81”}

警告:mysqli_stmt::bind_param()的参数2应为引用,值在。。。在线319

这应该是不言自明的:bind_param的参数是通过引用传递的,因此必须是变量。您可能忽略的是
array\u merge
返回的新数组不包含对原始变量的引用,只包含值

由于参数未绑定,因此随后会出现以下错误

一种可能的解决方案是将引用存储在
$parameters
数组中,这些引用甚至会被array\u merge保存:

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

$parameters[] =& $_POST["question"];
现在,
$parameters
的数组项是对POST变量的引用,
array\u merge
结果的数组项也是


编辑:看起来这已经不可能了,请参见

这是一个棘手的情况,它是由更改PHP5.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]);
}
我和你一样讨厌这个。我建议从
mysqli
切换到
PDO
,后者以一种更好的方式处理变量参数(在我看来,通常具有更好的语法):


这还不足以成为抛弃mysqli而使用PDO的理由,特别是当我当时有很好的理由不使用PDO时。另一方面,是的,它们不需要强制mysqli_stmt::bind_param和bind_result方法要求变量通过byRef传递,它们可以让它们返回一个数组。但是,这里真正的问题是不再可能通过引用传递调用时间,但是mysqli仍然需要通过引用传递,所以任何使用动态参数的人(任何拥有直观SQL的人)都会被这个问题所困扰,包括我自己。在花了数小时编写了一个自定义mysqli包装类,将数组集转换为动态准备的SQL语句之后,我不打算尝试重写它来使用PDO,特别是因为PDO需要将参数命名为绑定的一部分,我必须编写多个函数,以便为每种类型的查询生成发送内容的列表。这是违反直觉的,我不会浪费无数的时间去模仿我用mysqli所取得的成就

目前唯一的问题是我们无法在call_user_func_array()byRef中传递变量,而mysqli_stmt::bind_*需要在byRef中传递这些变量。。。因此,我们唯一的选择是1)编写一个新的call_user_func_array()函数,该函数专为bind_*方法显式工作,其中传递的参数基本上由args复制到一个新数组或一组变量中,然后在回调时传递这些byRef;或者2)重写mysqli类以正确的方式执行,只需查看传递的内容,执行SQL,然后按预期返回结果。我们传递给方法来执行SQL的内容没有理由一定会被结果打断,它应该像处理SQL控制台一样处理

因为我已经太累了,以至于我的眼睛都快流血了,所以我打算选择不建议的选项,将我的PHP版本保持在5.3.10-1,直到我真正以正确的方式解决问题。对于那些认为“为了所有这些努力,为什么不把它花在编写PDO包装器上呢?”。。。我的回答很简单:我在许多项目中只使用PHP和MySQL,其中服务器是一台空间和资源非常有限的小型计算机,更不用说CPU能力了。PDO加载它所能做的一切,而不仅仅是你将要使用的东西,所以在你的资源中有一些你甚至不会使用的东西,这是我的项目无法承受的损失

谢天谢地,现在保留我的PHP版本不会有什么坏处。这是许多企业级企业所做的
$pdo = new PDO('mysql:host=localhost', 'username', 'password');
$stmt = $pdo->prepare($selectedstudentanswerqry);
$stmt->execute($parameters);
$selectedstudentanswernum = $stmt->rowCount();