I'm losing my mind a little bit. I have two classess Database
and Medication [extends Database]
.
Class Database is a singleton class that constructs my PDO statement:
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>");
}
}
Connection works great, and non-prepared statements work great using it's query method:
protected function query($sql)
{
try {
$results = $this->conn->query($sql);
} catch (PDOException $pdo) {
exit("PDOException: " . $pdo->getMessage());
}
return $results;
}
In Medications, I am trying to protect my data as much as possible, so I'm trying to do prepared statements:
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;
}
When I try and use this method, it returns the following:
Fatal error: Uncaught Error: Call to undefined method Database::prepare()
Part of me understands that this is because my Database class does not have a prepare method in it. On the other hand, PDO does... PDO::prepare
So my question is - how do I utilize prepared statements from inside a child class of my Database class.
Also, as an FYI - I'm going to be adding more Classes as child classes of Database, which is why I'm trying to do it this way.
I'm also aware there's no ->execute(array()) in there. I'm trying to nail down part one of the issue before I extend it to execute.
Singletons are both global state, which causes difficult-to-debug issues, and locks you into only ever being allowed to have a single DB connection ever. Plus, for some reason you're trying to wrap all the functions that you could possibly call on a PDO object for no reason.
Eg:
class Foo {
public function __construct(protected \PDO $dbh) {}
public function doThing($args) {
foreach($args as $arg) {
$b = new Bar($this->dbh);
yield $b->something($arg);
}
}
}
class Bar {
public function __construct(protected \PDO $dbh) {}
public function something($arg) {
$stmt = $this->dbh->prepare(...);
$stmt->execute([$arg]);
return $stmt->fetchAll();
}
}
$dbh = new PDO(...);
$f = new Foo($dbh);
$f->doThing([1,2,3,4]);