2011-03-06 14 views
5

Tengo una clase de base de datos PHP que se conecta a MySQL y completa todo el código PDO y lo uso para consultar la base de datos. Básicamente en el controlador de la página hago un nuevo objeto:

$db = new Database($dbConfig); 

entonces puedo obtener datos de la base de datos al igual que el uso de una consulta preparada:

$params = array('username' => $username); 
$result = $db->preparedSelect('select password, salt from users where username = :username', $params); 

que copia los resultados de la instrucción de PDO en un nuevo Assoc array y devuelve solo los resultados de la base de datos a la página de llamada. Me iterar a través de ellos con un simple foreach así:

foreach ($result as $key => $val) 
{ 
    $password = $val['password']; 
    $salt = $val['salt']; 
} 

Ok lo que permite decir que quiero otra clase que se utiliza mi objeto $ db para que pueda acceder a la base de datos en algunos de los métodos. En el momento en que la otra clase es el siguiente:

class General 
{ 
    // Database object 
    private $db; 

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

que funciona bien, pero me pregunto si el constructor debe tener este aspecto:

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

Eso debería significar que estoy pasando en a través de referencia y no copiar el objeto en la otra clase. No quiero una copia del objeto $ db dentro de la clase, quiero que use el objeto de la base de datos existente, por lo que no tengo varias copias flotando en el uso de la memoria.

¿Hay alguna diferencia en PHP5 al pasarlo como $ db o & $ db? De hacer algo de lectura, PHP5 pasa por defecto objetos por referencia, y otras personas dicen que ahora lo hace de la manera Java y algunos dicen que usar el & hace un enlace duro sea lo que sea. Estoy confundido. ¿Cuál es la mejor manera de hacerlo?

¡Muchas gracias!

Respuesta

8

Hay una diferencia, pero en realidad no es la diferencia que pueda pensar.

En PHP5, "$ db" que contiene un objeto es básicamente equivalente a un "Foo *" en C o C++. En otras palabras, $ db no almacena todo el objeto, solo almacena un pequeño token que permite que el código encuentre el objeto cuando sea necesario. Cuando pasa este token por valor, es tan rápido como pasar un valor entero en lugar de una copia del objeto completo. Pero si asigna $ db, no cambia el valor en la persona que llama porque está cambiando su variable local que contiene el token para que contenga un token diferente.

Si la función de toma "& $ db", que es básicamente el equivalente de pasar "Foo **" en C, o más correctamente una función que toma un "Foo * &" en C++. La llamada es igual de rápida ya que es el mismo tamaño que se pasa, pero dentro de la función si asigna a $ db cambiará el valor de $ db en la persona que llama porque la variable "pasar por referencia" lo dirige a la memoria ubicación que contiene el token en la persona que llama.

La mejor manera de hacerlo es pasar por valor (no use "&") a menos que sepa lo que está haciendo y por qué lo hace.

+2

Entonces, esencialmente si hago _construct ($ db) y luego cambio un valor dentro del objeto $ db, p. Ej. $ db-> testvar = 1 Tendré dos objetos $ db en la memoria, el original y el nuevo en el que testvar contiene un '1'. ¿Está bien? Si hago _construct (& $ db) luego asigno $ db-> testvar = 1, debería afectar el objeto original y solo tengo una instancia del objeto $ db en la memoria. ¿Está bien? – zuallauz

+5

No, tendrá un objeto con el valor modificado en ambos casos, ya que en ninguno de los casos se está copiando el objeto. En la primera función, si hace '$ db = null' la persona que llama aún tendrá su $ db original, mientras que en la segunda función la persona que llama ya no tendrá el $ db original. – Anomie

3

Esa es una buena pregunta.

Siempre puede hacer una prueba abriendo un controlador $ db, pasarlo a una función y verificarlos a través del operador === para asegurarse de que son el mismo objeto.

+1

he hecho una prueba y que parecen ser el mismo objeto exacto. Creo que debes usar clone $ db para hacer una copia del objeto $ db original. De lo contrario, cualquier cambio que realice en el objeto $ db desde dentro de otra clase también actualizará el original. – zuallauz

3

Esto sería un buen trabajo para los métodos estáticos. Así es como muchos marcos logran la misma tarea.

class DB 
{ 
    private static $db = FALSE: 

    public static function init($dbConfig) 
    { 
     if(! self:$db) 
     { 
     self::$db = new Database($dbConfig); 
     } 
    } 

    public static function preparedSelect($sql, $params) 
    { 
     if(! self::$db) 
     { 
     die("call the init method first"); 
     } 

     // db stuff, where you would call $this->db call self::$db 
    } 
} 

Así que en sus otras clases en las que desea realizar llamadas a la base de datos todo lo que tendría que hacer es:

class General 
{ 
    public function __construct() 
    { 
     DB::init($dbConfig); 
    } 

    public function someMethod() 
    { 
     $params = array('username' => $username); 
     $result = DB::preparedSelect('select password, salt from users where username = :username', $params); 

    } 
} 
+1

Estaba a punto de utilizar métodos estáticos para esto, sin embargo, después de la investigación, demostró que las dependencias como las de su clase General (que actualmente es DB) no son evidentes de inmediato, y pueden causar confusión en el futuro. Los métodos estáticos/singletons no deberían usarse de esta forma, sino que * Dependency Injection * debe emplearse/pasar explícitamente la variable al constructor para que se pueda ver exactamente de qué dependen las clases :) – Jimbo

Cuestiones relacionadas