php Mysqli查询错误:参数#1($mysql)必须是mysqli类型,DB给定

irlmq6kh  于 5个月前  发布在  PHP
关注(0)|答案(2)|浏览(102)

难以理解如何获取新插入行的ID。
下面是我的过程化mysqli连接和SQL INSERT语句:

class DB {
    
    var $conn;
    function __construct($servername, $username, $password, $dbname, $dbport = 0000) {
        $this->conn = new mysqli($servername, $username, $password, $dbname, $dbport );         
    }
 
// Run a query
    public function query($sql) {
        return $this->conn->query($sql);
    }

// Clean incoming data
    public function clean($data) {
        return $this->conn->real_escape_string($data);
    }    
}
    
define("DB_HOST","localhost");
define("DB_USER","myusername");
define("DB_PASS","mypass");
define("DB_NAME","mydbname");
define("db",new DB(DB_HOST, DB_USER, DB_PASS, DB_NAME));

$sql = db->query("INSERT INTO my_table (field_one, field_two, field_three) VALUES ( 'test1', 'test2', 'test3')");

字符串
我想我可以做一些事情(like this):

if (mysqli_query(db, $sql)) {
    $last_id = mysqli_insert_id(db);
    echo "New record created. Last inserted ID is: " . $last_id;
} else {
    echo "Error: " . $sql . "<br>" . mysqli_error(db);
}


错误消息:

Fatal error: Uncaught TypeError: mysqli_query(): Argument #1 ($mysql) must be of type mysqli, DB given in /var/www/vhosts/***.****.com/httpdocs/admin/test.php:36
Stack trace: #0 /var/www/vhosts/***.****.com/httpdocs/admin/test.php(36): mysqli_query() #1 {main} thrown in /var/www/vhosts/***.****.com/httpdocs/admin/test.php on line 36 line 36


这将是第二个块的第一行:if (mysqli_query(db, $sql)) {

**我哪里错了?**真的很感激你的解释w/什么和为什么?

这也可能是一个愚蠢的问题,但在我在网上读到的例子中--没有一个与我的连接设置完全匹配--没有一个提到ID的列名是否重要?我的格式是“table_id”,而不仅仅是“id”,而且它被设置为自动增量。

b4wnujal

b4wnujal1#

如果你真的包含了错误信息,那将是很有帮助的,但是问题是你的DB类既不是Mysqli类的扩展,也没有实现相关的接口,因此你不能简单地将它放入需要Mysqli对象的函数中。正如ADyson已经提到的,你的 Package 类是不必要的,并且会在这里积极地妨碍你,因为它会在很多其他地方。
抛弃 Package 类,直接使用Mysqli对象。
此外,全局状态通常是一个坏主意,特别是对于数据库连接。它允许“幽灵般的远程操作”,也就是看起来完全不相关的代码,通过全局命名空间中的共享对象产生副作用,以及将您束缚在只能使用单个数据库连接而无需进行重大重写。
通常,最好将DB连接传递到需要它的调用或对象中,例如:

$db = new Mysqli(...);

foo($db, $arg1, $arg2);

$f = new Foo($db, ...);

字符串

wpcxdonn

wpcxdonn2#

不幸的是,无论下面的更改如何,您的代码都注定会失败,但是让我先解释一下为什么您会遇到这个问题,然后再解释为什么这仍然不起作用。

错误

您的DB类不是mysqli的类型,但可以通过将class DB更改为:

class DB extends mysqli

字符串
以下是正在发生的事情的细分:

<?php

// Defines a new class, DB, which is type DB.
class DB {}

// Defines "db" as an instance of the DB class, still type DB.
define("db",new DB(DB_HOST, DB_USER, DB_PASS, DB_NAME));

// This is trying to pass "db" as the first argument to mysqli_query().
if (mysqli_query(db, $sql)) {}


问题是mysqli_query期望以下内容:

function mysqli_query(
    mysqli $mysql,
    string $query,
    int|null $result_mode = MYSQLI_STORE_RESULT
): bool|mysqli_result


正如您所看到的,第一个参数需要类型mysqli,无论是直接用new mysqli()示例化还是间接用extends mysqli示例化。在DB内部示例化new mysqli的事实并没有什么不同,你可以复制整个mysqli类,但是如果你命名它为DB,它仍然会以那种方式输入,而没有扩展名。
一旦你做了这个改变,你的论点应该被接受。

问题

潜在的问题是DB类仍然不适合执行mysqli类代码。
如果你看一下mysqli class docs,你会注意到你的类没有被适当地设计来包含你的连接信息,并且最终会失败,因为你正在调用的函数不能访问$conn。你的 Package 器用于非常基本的用例来调用query()clean()方法,但仅此而已。它实际上并没有注入父mysqli类正常运行所需的必要信息。
从技术上讲,您可以通过使用getter暴露$conn来解决这个问题:

<?php
class DB {
    // ...other stuff
    public function getConn() {
        return $this->conn;
    }
}

mysqli_query(db->getConn(), $sql);


或者使用__toString()魔术方法,当您不调用其他方法(如db->query())时,该方法将始终将db视为连接。

<?php
class DB {
    // ...other stuff
    public function __toString() {
        return $this->conn;
    }
}

mysqli_query(db, $sql);


然而,这似乎真的不切实际,除非您有某种理由隐藏mysqli的其余功能。

Package 器

这将 * 几乎 * 适合于创建一个数据库 Package 器,其中包含与其自己的类中的mysqli_query等函数交互的逻辑,但它似乎不是您心目中的目标。
Package 器是有用的,因为它允许你在一个地方实现逻辑。你正在使用这个类之外的函数,需要mysqli,所以在这种情况下它实际上并不能帮助你。然而,一个正确的例子可能是这样的:

<?php
class DB {
    // ...other stuff
    public function db_query($sql) {
        return mysqli_query($this->conn, $sql);
    }
}

// Now, if you change databases you can just edit db_query.
db->db_query($sql);

子类

以这种方式构建类的正确方法是将__construct参数注入到父类中,但由于您正在尝试调用$connquery()方法,因此这也会导致数据库类的损坏示例。
一个如何正确构建子类的例子看起来像这样:

<?php
class DB extends mysqli {
    public function __construct($host, $user, $pass, $database, $port = 3306) {
        parent::__construct($host, $user, $pass, $database, $port);
    }

    // New custom methods go here.
}

// Now a fully functional mysqli child!
$db = new DB(DB_HOST, DB_USER, DB_PASS, DB_NAME);


我的建议是直接通过$db = new mysqli()创建一个示例,而不是通过任何这些抽象过程。虽然这种方式抽象类有它的用途,因为你仍然处于学习阶段,我认为它增加了额外的,不必要的复杂性。

相关问题