Каков наилучший метод для получения соединения / объекта базы данных в функцию в PHP? - PullRequest
4 голосов
/ 23 октября 2008

Несколько вариантов:

$connection = {my db connection/object};

function PassedIn($connection) { ... }

function PassedByReference(&$connection) { ... }

function UsingGlobal() {
    global $connection;
    ...
}

Итак, передано, передано по ссылке или с использованием global. Я имею в виду функции, которые используются только в 1 проекте, который будет иметь только 1 подключение к базе данных. Если имеется несколько соединений, то определенно передается или передается по ссылке.

Я полагаю, что передача по ссылке не требуется, когда вы используете PHP5 в объекте, поэтому передайте его или используйте global - две возможности.

Причина, по которой я спрашиваю, состоит в том, что я устаю всегда вставлять $ connection в параметры моей функции.

Ответы [ 6 ]

4 голосов
/ 23 октября 2008

Я использую класс Singleton ResourceManager для обработки таких вещей, как соединения с БД и настройки конфигурации через целое приложение:

class ResourceManager {
    private static $DB;
    private static $Config;

    public static function get($resource, $options = false) {
        if (property_exists('ResourceManager', $resource)) {
            if (empty(self::$$resource)) {
                self::_init_resource($resource, $options);
            }
            if (!empty(self::$$resource)) {
                return self::$$resource;
            }
        }
        return null;
    }

    private static function _init_resource($resource, $options = null) {
        if ($resource == 'DB') {
            $dsn = 'mysql:host=localhost';
            $username = 'my_username';
            $password = 'p4ssw0rd';
            try {
                self::$DB = new PDO($dsn, $username, $password);
            } catch (PDOException $e) {
                echo 'Connection failed: ' . $e->getMessage();
            }
        } elseif (class_exists($resource) && property_exists('ResourceManager', $resource)) {
            self::$$resource = new $resource($options);
        }
    }
}

А затем в функциях / объектах / где-либо:

function doDBThingy() {
    $db = ResourceManager::get('DB');
    if ($db) {
        $stmt = $db->prepare('SELECT * FROM `table`');
        etc...
    }
}

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

2 голосов
/ 23 октября 2008

Я вижу, что многие люди предложили какую-то статическую переменную.

По сути, между глобальной переменной и статической переменной очень мало различий. За исключением синтаксиса, они имеют абсолютно одинаковые характеристики. Таким образом, вы вообще ничего не получаете, заменяя глобальную переменную статической переменной. В большинстве примеров существует уровень разделения, в котором статическая переменная не указывается напрямую, а скорее статическим методом (например, одноэлементный или статический реестр). Хотя и немного лучше, это все еще имеет проблемы глобального масштаба. Если вам когда-либо понадобится использовать более одного подключения к базе данных в вашем приложении, вы облажались. Если вы когда-нибудь захотите узнать, какие части вашего кода имеют побочные эффекты, вам нужно вручную проверить реализацию. Это не то, что сделает или сломает ваше приложение, но усложнит его обслуживание.

Я предлагаю вам выбрать одно из:

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

  • Поместите экземпляр в область объекта, у которого есть метод, который нуждается в нем. Например. если для метода Foo->doStuff() требуется соединение с базой данных, передайте его в конструктор Foo и установите его в качестве переменной защищенного экземпляра на Foo. Вы все еще можете столкнуться с некоторыми проблемами передачи в методе, но это обычно меньше проблем с громоздкими конструкторами, чем с методами. Если ваше приложение становится достаточно большим, вы можете использовать контейнер внедрения зависимостей, чтобы автоматизировать это.

2 голосов
/ 23 октября 2008

Попробуйте разработать свой код объектно-ориентированным способом. Методы, которые используют базу данных, должны быть сгруппированы в классе, а экземпляр класса должен содержать соединение с базой данных как переменную класса. Таким образом, соединение с базой данных доступно для функций, которым оно необходимо, но оно не является глобальным.

class MyClass {
  protected $_db;

  public function __construct($db)
  {
    $this->_db = $db;
  }

  public function doSomething()
  {
    $this->_db->query(...);
  }
}
1 голос
/ 23 октября 2008

Мой совет - избегать глобальных изменений в коде - это опасно, трудно отследить и укусит вас.

Способ, которым я бы это сделал, - это получить функцию getDB (), которая может быть либо на уровне класса посредством внедрения конструктора, либо статической в ​​общем классе.

Таким образом, код становится

class SomeClass {
    protected $dbc;

    public function __construct($db) {
        $this->dbc = $db;
    }

    public function getDB() {
        return $this->dbc;
    }

    function read_something() {
        $db = getDB();
        $db->query();
    }
}

или используя общий разделяемый класс.

function read_something() {
    $db = System::getDB();
    $db->query();
}

Независимо от того, какой элегантный дизайн системы вы делаете, всегда есть несколько элементов, которые обязательно являются глобальными по объему (например, DB, Session, Config), и я предпочитаю сохранять их как статические методы в моей системе класс.

Лучше всего это сделать для каждого класса, требующего соединения через конструктор, я имею в виду самое надежное и изолированное.

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

0 голосов
/ 23 октября 2008
function usingFunc() {
  $connection = getConnection();
  ...
}

function getConnection() {
  static $connectionObject = null;
  if ($connectionObject == null) {
    $connectionObject = connectFoo("whatever","connection","method","you","choose");
  }
  return $connectionObject;
}

Таким образом, статический $ connectionObject сохраняется между вызовами getConnection.

0 голосов
/ 23 октября 2008

Ничего из перечисленного.

Все функции mysql принимают аргумент подключения к базе данных , необязательно . Если вы пропустите этот аргумент, предполагается, что последнее соединение с помощью mysql_connect ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...