Передача соединения по ссылке в PHP

Вопрос в том, должно ли соединение базы данных передаваться по ссылке или по значению?

Для меня я специально задаю вопрос о подключении PHP к MySQL, но я думаю, что это относится ко всем базам данных.

Я слышал, что в PHP, когда вы передаете переменную функции или объекту, она копируется в память и поэтому сразу использует вдвое больше памяти. Я также слышал, что он копируется только после внесения изменений в значение (например, добавляемый/удаляемый ключ из массива).

В соединении с базой данных я бы подумал, что он изменяется в функции, поскольку запрос может изменить такие вещи, как последний идентификатор вставки или число строк. (Я думаю, это еще один вопрос: такие вещи, как num rows и insert id, хранящиеся в соединении, или фактический вызов возвращается в базу данных?)

Итак, имеет ли значение память или скорость, если соединение передается по ссылке или значению? Это имеет значение PHP 4 против 5?

// $connection is resource
function DoSomething1(&$connection) { ... }
function DoSomething2($connection) { ... }

Ответ 1

Ресурс PHP - это особый тип, который уже является ссылкой сам по себе. Передача его по значению или явно по ссылке не будет иметь никакого значения (т.е. Это еще ссылка). Вы можете проверить это для себя в PHP4:

function get_connection() {
  $test = mysql_connect('localhost', 'user', 'password');
  mysql_select_db('db');
  return $test;
}

$conn1 = get_connection();
$conn2 = get_connection(); // "copied" resource under PHP4

$query = "INSERT INTO test_table (id, field) VALUES ('', 'test')";
mysql_query($query, $conn1);
print mysql_insert_id($conn1)."<br />"; // prints 1

mysql_query($query, $conn2);
print mysql_insert_id($conn2)."<br />"; // prints 2

print mysql_insert_id($conn1); // prints 2, would print 1 if this was not a reference

Ответ 2

Это не та скорость, о которой вы должны беспокоиться, но память.

В PHP 4 такие вещи, как соединения с базой данных и результаты, должны быть явно переданы по ссылке. В PHP 5 это делается автоматически, поэтому вам не нужно делать это явным.

Кстати, методы singleton для создания дескрипторов баз данных - хорошая идея: вы можете сделать $db = & Database::Connection(); и всегда получать правильный дескриптор. Это избавит вас от использования глобального, и статический метод может сделать дополнительную магию (например, автоматически открыть ее) для вас. Просто будьте осторожны, когда ваше приложение масштабируется настолько, что ему нужно несколько баз данных: тогда ваша волшебная функция должна будет знать, как вернуть вам правильный. IME это не очень сложно; основной способ решить это для слоя кода, которому нужен дескриптор DB, чтобы узнать, как запросить правильный.

Ответ 3

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

Лично я использую класс singleton- factory для моих подключений к базе данных, и всякий раз, когда мне нужна ссылка на базу данных, я просто вызываю Factory:: database(), поэтому мне не нужно беспокоиться о нескольких подключениях или передачи/приема ссылок.

<?php
Class Factory
{
  private static $local_db;

/**
* Open new local database connection
*
* @return MySql
*/
public static function localDatabase() {
    if (!is_a(self::$local_db, "MySql")) {
        self::$local_db = new MySql(false);
        self::$local_db->connect(DB_HOST, DB_USER, DB_PASS, DB_DATABASE);
        self::$local_db->debugging = DEBUG;
    }
    return self::$local_db;
}
}
?>

Ответ 4

Соединение с базой данных фактически не содержит базовые значения, поэтому вам не нужно беспокоиться о потере назначений внутри функции. Метафорически вы можете думать о соединении с БД, как, скажем, номер ВПП - "ОК, DB Connection 12 очищается для использования для запроса" - запрос и результирующий набор используют соединение и могут нуждаться в эксклюзивном доступе для некоторое время, но соединение ничего не знает о базовых данных.

Ответ 5

Несколько человек сказали, что вам не нужно беспокоиться об этом для PHP 5. Это неверно, если у вас есть OBJECT базы данных, который вы используете для всего доступа. В этом случае вам необходимо передать по ссылке, иначе он создает экземпляр нового объекта базы данных, который (часто) создает новое соединение с базой данных.

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

Чтобы пояснить: причина, по которой я указываю, что это обычный способ использования соединений с базой данных, а не ресурс необработанного соединения.

Ответ 6

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

Ответ 7

Вообще говоря, ссылки не быстрее в PHP. Это распространенное заблуждение, потому что они семантически похожи на C-указатели, поэтому люди, знакомые с C, часто предполагают, что они работают одинаково. Не так. На самом деле, ссылки немного медленнее копий, если только вы не назначаете эту переменную (что в любом случае является плохим стилем, если только переменная не является объектом).

PHP имеет механизм, называемый copy-on-write, что означает, что переменная на самом деле не скопирована до ее необходимости. Вы можете передать огромную структуру данных функции; Пока он только что читает, это не имеет значения. Однако для справки требуется дополнительная запись во внутренних регистрах, поэтому на самом деле потребуется дополнительная обработка (хотя и едва заметная).