PHP Mysqli Соединение через несколько классов

0

Итак, я устал от PHP, но большую часть времени я использовал процедурный стиль. Я всегда старался следовать шаблону MVC, хотя я делал вещи процедурно. Кроме того, я привык к некоторым фреймворкам, таким как CakePHP и CodeIgniter. Тем не менее, я еще ничего не сделал с нуля, используя ООП. Сегодня я делаю это для работы в колледже, и у меня есть несколько вопросов.

Обычно в рамках мы просто выполняем $this->database->query(), в любом классе контроллера, и он работает. В процедуре $link с базой данных имеет глобальный масштаб, поэтому вам не нужно беспокоиться. Я искал способ сделать это с каждым классом в своем коде, но безуспешно. Лучшее, что я мог получить, это использовать класс Singleton для создания базы данных, однако мне нужно было получить ссылку на базу данных в каждом отдельном классе. Так, например, в классе Users я должен был бы получить его в конструкторе, и в классе Main, и в любом другом.

Мои вопросы довольно просты. Как использовать ссылку на соединение с базой данных через несколько классов, без необходимости создавать экземпляр db во всех них. И если это самый лучший способ, есть ли другой способ сделать это, чем метод Singleton?

Mysqli, я использую Mysqli lib.

Здесь класс, который я использовал.

class DB extends Mysqli {
    protected static $instance;

    private function __construct() {
        global $config;

        parent::__construct($config['db']['host'], $config['db']['user'], $config['db']['password'], $config['db']['database']);

        if($this->connect_error)
            die('Connect Error ('. $mysqli->connect_errno .') '. $mysqli->connect_error);
    }

    public static function getInstance() {
        if( !self::$instance ) {
            self::$instance = new self(); 
        }
        return self::$instance;
    }
}

Вот пример использования класса.

class Main {
    protected $db;

    public function __construct() {
        $this->db = DB::getInstance(); // <-- having to do that in every class is the problem
    }

    protected function start() {
        $this->db->query(something...); // works
    }
}
Теги:
database
class
mysqli
singleton

3 ответа

0
Лучший ответ

Если вы создаете суперкласс с помощью магического метода __get, вы можете проверить, является ли имя запрашиваемого свойства db, и если это так, то автоматически получите экземпляр из вашего класса DB, и если не ошибка, как обычно:

<?php
class Super
{
    public function __get($name)
    {
           if($name=="db") {
                     return DB::getInstance();
           } else {
                     trigger_error("Undefined property", E_USER_NOTICE);
           }
    }
}
?>
  • 0
    Это устраняет одну из проблем исходного метода Singleton, которая не позволяет вызывать разные экземпляры базы данных. Но главная проблема сохраняется.
  • 0
    Ааа, видите, я думал, что вы имели в виду, что вам не нужно создавать экземпляр базы данных, которую вы имели в виду, вместо того, чтобы явно вызывать метод для инициализации переменной. Для решения, которое вы в итоге придумали (не хватает для редактирования), вы можете использовать метод __get в классе Super. Там вы можете проверить, является ли имя искомого свойства db, если да, то getDBConn (), если нет, то вывести ошибку как обычно. Я сделаю правку, чтобы показать, что я имею в виду.
Показать ещё 4 комментария
1

Лучше всего использовать инъекцию зависимостей вместо инициирования соединения в каждом классе:

$db = DB::getInstance(); // or any other way to initiate it
$obj1 = new MyClass1($db);
$obj2 = new MyClass2($db);

Таким образом, вы всегда решаете, какую БД вы хотите передать каждому классу. Кроме того, это дает некоторые преимущества, если вы также проводите модульное тестирование - тогда вы можете протестировать каждый класс, предоставив ссылку на тестовую БД или даже издеваясь над ней.

  • 0
    Спасибо за такой простой пример внедрения зависимостей. Я выглядел очень впечатляюще из-за всех его сложностей.
  • 0
    Правильно. Собственно, именно таким способом я и попробовал первое, за исключением инициации соединения db вне класса, а затем передачи его через аргументы в основной класс. Тем не менее, я подумал, что очень плохо - передавать ссылку db в каждом конструкторе, а затем делать $this->db = $db чтобы получить доступ к ссылке во всем классе, в каждом классе. Все сводилось к тому же, что и к синглтон-классу.
0

Итак, я придумал свой собственный ответ. Я не уверен, что это оптимальный способ, но вот он. Используя тот же класс DB, что и вопрос, я создал класс "Супер", чтобы "удерживать" ссылку на базу данных при построении. Таким образом, пока я не использую конструктор для других классов, я могу расширить класс "Супер" и получить доступ к $this->db без необходимости определять его в каждом классе. Если конструктор действительно нужен, я могу вызвать parent::__construct() из него, и он также будет работать.

class Super {
    protected $db;

    public function __construct() {
        $this->db = DB::getInstance();
    }
}

class Main extends Super {

    /* No constructor, 
       otherwise it will overwrite the Super 
       constructor and lack what we've done there. */

    public function start() {
        $this->db->query(something...); // works
    }

}

Я также ввел некоторые другие переменные и функции, которые были необходимы в нескольких классах. Оттуда я могу выбрать, где продлить или нет класс "Супер", когда это необходимо.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню