如何在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连接
- 修正
Medication类的构造方法,调用父类构造初始化PDO连接:
public function __construct() { parent::__construct(); }
- 在
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
相关产品推荐
相关产品推荐

