Внедрение PHP PDO внутри класса

Я пытаюсь понять, как использовать 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.";
        }
    }

}

Исправьте цитаты для правильного выделения.

u_mulder 01.06.2018 12:13

Исправьте эту строку return $ this-> db = new PDO ('mysql: host = localhost; dbname = testdb;', 'root', 'root');

executable 01.06.2018 12:15

Цитаты исправлены, извините за опечатку!

user9741470 01.06.2018 12:16

Вы передаете экземпляр Database в сторону User, а не экземпляр PDO. Либо создайте геттер / сеттер для обработчика базы данных в Database, например getConnection(), а затем вы можете сделать $this->db->getConnection()->prepare, либо просто избавьтесь от инкапсуляции и просто передайте экземпляр PDO в сторону User.

DarkBee 01.06.2018 12:20

@DarkBee, не могли бы вы привести пример?

user9741470 01.06.2018 12:21

@DarkBee Я не хочу создавать более одного соединения PDO.

user9741470 01.06.2018 12:24
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
6
651
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы должны создать геттер для фактического соединения, если хотите инкапсулировать соединение 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()?

user9741470 01.06.2018 12:38

Когда я начал писать этот код, я использовал класс User, добавляя зависимость PDO внутри конструкции, подобной этой __construct(PDO $db).

user9741470 01.06.2018 12:41

Что заставило вас отказаться от этого подхода? Если вы не собираетесь добавлять больше логинов к классу Database, кроме сохранения обработчика, вы должны передать экземпляр PDO, как и раньше.

DarkBee 01.06.2018 12:49

Если вы хотите избежать части getConnection(), это будет означать, что вам нужно либо связать каждый метод PDO в вашем классе Database, либо позволить Database расширяться от PDO, но тогда вы вернетесь к своему началу

DarkBee 01.06.2018 12:50

@ user9741470 ваш первый подход более ясен. Вы знаете, с какими объектами и методами имеете дело. Если я посмотрю на класс пользователя выше, я не пойму, что это за объект базы данных.

Progrock 01.06.2018 12:56

@DarkBee Я отказался от инъекции в конструкцию, потому что каждый раз, когда консоль сообщала, что я не передал экземпляр PDO в конструктор класса, и это потому, что, вероятно, по моему незнанию я каждый раз передавал переменную $db в конструкцию.

user9741470 01.06.2018 13:40

Я не знаю, работаете ли вы с пространствами имен, но если вы это сделаете, подпись метода должна быть public function __construct(\PDO $db) {, иначе PHP будет искать PDO в текущем пространстве имен, а не в фактическом (корневом) PDO.

DarkBee 01.06.2018 14:02

@DarkBee на данный момент я еще не реализовал пространства имен, так что, может быть, ошибка из-за этого? учтите, что PDO реализован внутри класса Database, как показано в коде этого вопроса, поэтому он находится в конструкции. Как вы думаете, если я изменю эту реализацию, как вы предлагали, public function __construct(\PDO $db), она будет работать?

user9741470 01.06.2018 14:10

Да, я добавил код к ответу, чтобы отразить это

DarkBee 01.06.2018 14:17

@DarkBee, спасибо, я не знал об этом. Я недавно использую ООП, поэтому некоторые концепции для меня новы.

user9741470 01.06.2018 14:48

@DarkBee только последний вопрос, мне нужно инициализировать PDO вне классов, правильно? Как я вижу из вашего примера, это экземпляр, созданный вне класса.

user9741470 01.06.2018 14:50

Да, просто поместите в файл с именем db.php и сделайте require_once 'db.php';, чтобы убедиться, что у вас только одно соединение

DarkBee 01.06.2018 14:57

Ок, прекрасно. Первоначально я пытался избежать этого подхода, но если это лучший метод, я буду следовать ему.

user9741470 01.06.2018 15:00

Другие вопросы по теме

Запрос доступа к PDO
ОШИБКА PDO: PDOStatement :: execute (): SQLSTATE [HY093]: недопустимый номер параметра: количество связанных переменных не соответствует количеству токенов
Выберите данные на основе администратора и уровня, который вошел в систему, но он отображает данные с другого уровня
Количество связанных переменных не соответствует количеству токенов при использовании пользовательской функции PDO
Ввод с подстановочными знаками заставляет другие входы поиска извлекать все данные в форме поиска с несколькими входами
Как я могу заменить или удалить специальный символ из файла перед загрузкой в ​​базу данных и перед перемещением в каталог?
PDO Получить ошибку из определенного оператора
Ошибка обработки PDO с помощью метода query () или prepare ()
PHP pdo: неверный номер параметра при использовании параметра дважды?
Вставка в sql из php дает ошибку SQLSTATE [HY093]