You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PHP子类中使用PDO预处理语句

问题:子类调用PDO预处理方法触发未定义方法错误

现有Database单例类和继承它的Medication类,Database类在构造方法中创建PDO连接,自带的query方法可执行非预处理语句,连接及该方法均正常工作。

在Medication类中尝试使用PDO预处理语句编写edit_med_by_keyID方法时,调用$this->conn->prepare($sql)触发报错:

Fatal error: Uncaught Error: Call to undefined method Database::prepare()

已知PDO本身具备prepare方法,但Database类未封装该方法,需要解决如何在Database的子类中使用PDO预处理语句(后续会新增更多继承Database的子类)。注:暂未添加execute方法,先解决当前报错。


相关代码

Database类构造方法

protected function __construct()
{
    require_once(PRIVATE_PATH . "/config/db_credentials.php");
    try {
        $this->conn = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USER, DB_PASS);
        $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $pdo) {
        exit("PDOException: " . $pdo->getMessage() . "<br><br>");
    }
}

Database类query方法

protected function query($sql)
{
    try {
        $results = $this->conn->query($sql);
    } catch (PDOException $pdo) {
        exit("PDOException: " . $pdo->getMessage());
    }
    return $results;
}

Medication类代码

public function __construct()
{
    $this->conn = Database::getInstance();
}

public function edit_med_by_keyID($keyID, $attributes)
{
    try {
        $attributes['keyID'] = (int) $keyID;
        $sql = "UPDATE medications 
                SET `rxID` = :rxID,
                    `name` = :name,
                    `aka` = :aka,
                    `dosage` = :dosage,
                    `instructions` = :instructions,
                    `prescriber` = :prescriber,
                    `specialty` = :specialty,
                    `category` = :category,
                    `type` = :type,
                    `status` = :status,
                    `notes` = :notes
                WHERE `keyID` = :keyID LIMIT 1";
        $this->conn->prepare($sql);
    } catch (PDOException $pdo) {
        exit("PDOException: " . $pdo->getMessage());
    } catch (Exception $ex) {
        exit("Exception: " . $ex->getMessage());
    }

    return;
}

核心错误分析

你的Medication类构造方法中,$this->conn = Database::getInstance();把$this->conn赋值成了Database单例实例,而非PDO连接对象。Database类内部的$conn是protected属性的PDO对象,子类可以直接继承访问,不需要重新赋值为父类实例。


解决方案

方式一:直接使用父类的PDO连接

  1. 修正Medication类的构造方法,调用父类构造初始化PDO连接:
public function __construct()
{
    parent::__construct();
}
  1. 在edit_med_by_keyID方法中,直接通过继承的$this->conn(PDO对象)调用prepare:
$stmt = $this->conn->prepare($sql);

方式二:在Database类中封装prepare方法(推荐)

如果希望所有子类复用统一的异常处理逻辑,在Database类中添加prepare方法:

protected function prepare($sql)
{
    try {
        return $this->conn->prepare($sql);
    } catch (PDOException $e) {
        exit("PDOException: " . $e->getMessage());
    }
}

子类中直接调用该方法即可:

$stmt = $this->prepare($sql);

这种方式的优势是后续修改预处理的异常逻辑或扩展功能时,只需修改父类代码,所有子类自动生效。


内容的提问来源于stack exchange,提问作者jpgerb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 01:42:53