Я пытаюсь понять, как использовать PDO внутри класса. Я написал этот простой класс, который содержит соединение PDO, которое передается как часть __construct() внутри другого класса. Проблема в том, что каждый раз, когда я пытаюсь использовать метод класса, которому требуется соединение с базой данных, я получаю сообщение об ошибке, которое связано со встроенными функциями PDO, такими как prepare(), execute(). Ошибка - PHP Fatal error: Uncaught Error: Call to undefined method Database::prepare(). Как я могу решить эту проблему? Я читал о внедрении зависимостей, но сейчас это немного сбивает с толку, как применить этот шаблон к коду при использовании PDO.
<?php
class Database {
public function __construct() {
return $this->db = new PDO("mysql:host=localhost;dbname=testdb;", "root", "root");
}
}
class user {
public function __construct($db) {
$this->db = $db;
}
public function createUser($email, $username, $password) {
$stmt = $this->db->prepare("INSERT INTO users (email,username,password) VALUES (?, ?, ? )");
if ($stmt->execute(array($email, $username, $password))) {
echo "Account successful created";
} else {
echo "Something was wrong during the registration process.";
}
}
public function loginUser($username, $password) {
$stmt = $this->db->prepare("SELECT email,username,password FROM users WHERE email = ? OR username = ?");
$stmt->execute(array($username, $username));
if ($stmt->rowCount() > 0) {
$result = $stmt->fetch(PDO::FETCH_OBJ);
if (password_verify($password, $result->password)) {
echo "logged";
} else {
echo "wrong password";
}
} else {
echo "Username or email does not exist in the database.";
}
}
}
Исправьте эту строку return $ this-> db = new PDO ('mysql: host = localhost; dbname = testdb;', 'root', 'root');
Цитаты исправлены, извините за опечатку!
Вы передаете экземпляр Database в сторону User, а не экземпляр PDO. Либо создайте геттер / сеттер для обработчика базы данных в Database, например getConnection(), а затем вы можете сделать $this->db->getConnection()->prepare, либо просто избавьтесь от инкапсуляции и просто передайте экземпляр PDO в сторону User.
@DarkBee, не могли бы вы привести пример?
@DarkBee Я не хочу создавать более одного соединения PDO.






Вы должны создать геттер для фактического соединения, если хотите инкапсулировать соединение PDO в дополнительный класс.
<?php
class Database {
private $dbh = null;
public function __construct($user, $pass, $database) {
$this->dbh = new PDO("mysql:host=localhost;dbname = ".$database.";", $user, $pass);
}
public function getConnection() {
return $this->dbh;
}
}
class User {
private $db = null;
public function __construct($db) {
$this->db = $db;
}
public function createUser($email, $username, $password) {
$stmt = $this->db->getConnection()->prepare("INSERT INTO users (email,username,password) VALUES (?, ?, ? )");
if ($stmt->execute(array($email, $username, $password))) {
echo "Account successful created";
}else {
echo "Something was wrong during the registration process.";
}
}
}
}
$user = new User(new Database('root', 'root', 'testdb'));
Из комментариев:
В вашем случае было бы лучше просто передать экземпляр PDO вашим классам. Это должно работать:
<?php
class user {
public function __construct(\PDO $db) {
$this->db = $db;
}
}
<?php
/** Init the one and only DB connection for this request **/
$dbh = new PDO("mysql:host=localhost;dbname = ".$database.";", $user, $pass);
//... Do some stuff
//....
$user = new User($dbh);
Я протестировал код и работает без сбоев. Можно ли каким-то образом избежать использования getConnection()?
Когда я начал писать этот код, я использовал класс User, добавляя зависимость PDO внутри конструкции, подобной этой __construct(PDO $db).
Что заставило вас отказаться от этого подхода? Если вы не собираетесь добавлять больше логинов к классу Database, кроме сохранения обработчика, вы должны передать экземпляр PDO, как и раньше.
Если вы хотите избежать части getConnection(), это будет означать, что вам нужно либо связать каждый метод PDO в вашем классе Database, либо позволить Database расширяться от PDO, но тогда вы вернетесь к своему началу
@ user9741470 ваш первый подход более ясен. Вы знаете, с какими объектами и методами имеете дело. Если я посмотрю на класс пользователя выше, я не пойму, что это за объект базы данных.
@DarkBee Я отказался от инъекции в конструкцию, потому что каждый раз, когда консоль сообщала, что я не передал экземпляр PDO в конструктор класса, и это потому, что, вероятно, по моему незнанию я каждый раз передавал переменную $db в конструкцию.
Я не знаю, работаете ли вы с пространствами имен, но если вы это сделаете, подпись метода должна быть public function __construct(\PDO $db) {, иначе PHP будет искать PDO в текущем пространстве имен, а не в фактическом (корневом) PDO.
@DarkBee на данный момент я еще не реализовал пространства имен, так что, может быть, ошибка из-за этого? учтите, что PDO реализован внутри класса Database, как показано в коде этого вопроса, поэтому он находится в конструкции. Как вы думаете, если я изменю эту реализацию, как вы предлагали, public function __construct(\PDO $db), она будет работать?
Да, я добавил код к ответу, чтобы отразить это
@DarkBee, спасибо, я не знал об этом. Я недавно использую ООП, поэтому некоторые концепции для меня новы.
@DarkBee только последний вопрос, мне нужно инициализировать PDO вне классов, правильно? Как я вижу из вашего примера, это экземпляр, созданный вне класса.
Да, просто поместите в файл с именем db.php и сделайте require_once 'db.php';, чтобы убедиться, что у вас только одно соединение
Ок, прекрасно. Первоначально я пытался избежать этого подхода, но если это лучший метод, я буду следовать ему.
Исправьте цитаты для правильного выделения.