2008-10-27 7 views
11

La pregunta es si una conexión de base de datos debe pasarse por referencia o por valor?Pasar la conexión de la base de datos por referencia en PHP

Para mí específicamente estoy cuestionando una conexión de PHP a MySQL, pero creo que se aplica a todas las bases de datos.

He oído que en PHP cuando pasa una variable a una función u objeto, se copia en la memoria y, por lo tanto, utiliza el doble de memoria inmediatamente. También he oído que solo se copia una vez que se han realizado cambios en el valor (como una clave que se agrega/elimina de una matriz).

En una conexión de base de datos, creo que se está cambiando dentro de la función, ya que la consulta podría cambiar cosas como la última inserción de id o filas numéricas. (Supongo que esta es otra pregunta: ¿hay cosas como filas num e ID de inserción almacenadas en la conexión o se realiza una llamada real a la base de datos?)

Entonces, ¿importa la memoria o la velocidad si se pasa la conexión? por referencia o valor? ¿Hace una diferencia PHP 4 vs 5?

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

Respuesta

16

Un recurso de PHP es un tipo especial que ya es una referencia en sí mismo. Pasarlo por valor o explícitamente por referencia no hará la diferencia (es decir, sigue siendo una referencia). Esto se puede comprobar por sí mismo bajo 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 
4

El tiempo de referencia de la llamada por referencia se está depreciando, por lo que no utilizaría el método descrito por primera vez. Además, en términos generales, los recursos se pasan por referencia en PHP 5 de manera predeterminada. Por lo tanto, no debe exigirse ninguna referencia, y nunca debe abrir más de una conexión de base de datos a menos que realmente lo necesite.

Personalmente, utilizo una clase singleton-factory para las conexiones de mi base de datos, y cada vez que necesito una referencia de base de datos solo llamo a Factory :: database(), así no tengo que preocuparme por las conexiones múltiples o por pasar/recibiendo referencias

<?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; 
} 
} 
?> 
+2

"function DoSomething1 (& $ connection) {...}" no es call-time pass-by-reference –

+1

Iba a decir lo mismo que tom - eso NO es pass-by- referencia que, como su nombre lo indica, se produce en el momento de la función. llamando, no declaración El tiempo de referencia de la llamada por referencia se parece a este

+1

El estado global suele ser una mala respuesta a cualquier problema. – troelskn

0

que realmente no tienen una respuesta específica para php, pero en general me parece que usted quiere pasar esta por referencia si no está seguro de que de manera explícita se encuentra con problemas de rendimiento al pasar por valor.

1

Una base de datos de conexión en realidad no contener los valores subyacentes, por lo que no tiene que preocuparse por la pérdida de las asignaciones hechas dentro de una función. Metafóricamente, puede pensar en una conexión DB como, por ejemplo, un número de pista - "OK, la conexión DB 12 está desactivada para usarse para una consulta" - La consulta y el conjunto de resultados usan la conexión, y pueden necesita acceso exclusivo por un tiempo, pero la conexión no sabe nada sobre los datos subyacentes.

0

En general, las referencias no son más rápidas en PHP. Es un error común, porque son semánticamente similares a los indicadores C, por lo que las personas familiarizadas con C a menudo suponen que funcionan de la misma manera. No tan. De hecho, las referencias son un poco más lentas que las copias, a menos que se asigne a la variable (que en cualquier caso es un estilo incorrecto, a menos que la variable sea un objeto).

PHP tiene un mecanismo llamado copy-on-write, lo que significa que una variable no es en realidad copiada antes de que sea necesario. Puede pasar una gran estructura de datos a una función; Mientras solo lea de él, no hace ninguna diferencia.Sin embargo, una referencia necesita una entrada adicional en los registros internos, por lo que en realidad requerirá un procesamiento adicional (aunque apenas perceptible).

1

Algunas personas han dicho que no necesita preocuparse por esto para PHP 5. Esto es incorrecto, si tiene un OBJETO de base de datos que está utilizando para todos los accesos. En ese caso, debe pasar por referencia; de lo contrario, creará una instancia de un nuevo objeto DB, que (a menudo) crea una nueva conexión a la base de datos.

Descubrí esto usando XDebug & WinCacheGrind, que muestra amablemente todos los destructores que son llamados, en mi caso, una docena o más de objetos de base de datos.

Para aclarar: La razón por la que señalo esto es que esta es una forma común de usar conexiones de base de datos, en lugar del recurso de conexión sin formato.

5

No es la velocidad con la que debe preocuparse, sino la memoria.

En PHP 4, cosas como conexiones de bases de datos y resultados deberían pasarse explícitamente por referencia. En PHP 5, esto se hace automáticamente, por lo que no es necesario que sea explícito.

Por cierto, los métodos únicos para crear identificadores de bases de datos son una buena idea: puede hacer $db = & Database::Connection(); y obtener siempre el identificador correcto. Esto le ahorra el uso de un método global y estático puede hacer magia extra (como abrirlo automáticamente) para usted. Solo tenga cuidado de cuando su aplicación se desarrolle lo suficiente como para necesitar múltiples bases de datos: entonces su función mágica deberá saber cómo devolverle la correcta. IME esto no es muy difícil; la forma básica de resolver eso es que la capa de código que necesita el identificador de DB sepa cómo solicitar la correcta.

Cuestiones relacionadas