2011-01-06 14 views
8

Ho appena iniziato a utilizzare OOP PHP e mi sono imbattuto in una domanda. Ho creato una classe mysql generica che mi permette di connettersi a un database e ha alcune funzioni per ottenere record da una tabella:PHP OOP: come utilizzare una classe MySQL generica in altre classi

class mysql{ 
    //some lines to connect, followed by: 
    public function get_record($sql) 
    { 
     $result = mysql_result(mysql_query($sql)); 
     return $result; 
     //obiously it's a bit more advanced, but you get the picture. 

    } 
} 

Avanti, ho una classe per ottenere i dettagli dell'utente:

class user{ 
    __construct($id) 
    { 
     $this->id = $id 
    } 
    public function get_username($id) 
    { 
     $username = get_record("SELECT name FROM users WHERE id = '".$this->id."'"); 
     return $username; 
    } 
} 

Ho provato questo, ma ho ottenuto l'errore che la funzione get_record era sconosciuta. Ho risolto questo aggiungendo $ mysql = new mysql(); alla classe utente.

Tuttavia, sembra abbastanza inefficiente dover istanziare l'oggetto mysql per ogni classe che utilizza i miei metodi di database (è praticamente tutto).

C'è un modo per rendere la classe mysql ei suoi metodi accessibili a tutte le altre classi, senza dover chiamare la classe mysql in ogni metodo?

+1

Per favore, non creare classi MySQL. Ce ne sono troppi in giro, anche quando PHP ha già incorporato una cosa del genere. Si chiama PDO (PHP Database Objects). La PDO è trasferibile ad altri sviluppatori, mentre dovendo capire la classe MySQL di qualcun altro ancora e ancora si sente piuttosto inutile. – kander

risposta

1

È necessario passare l'oggetto mysql a ciascun oggetto utente. Quindi sarebbe simile a questa:

$mysql = new mysql(); 
$user = new user($mysql, $id); 
$name = $user->get_username(); 

class user { 
    public function __construct($mysql, $id) { 
     $this->mysql = $mysql; 
     $this->id = $id; 
    } 
    public function get_username() { 
     $username = $this->mysql->get_record("SELECT name FROM users WHERE id = '".$this->id."'"); 
     return $username; 
    } 
} 
1

progettare la vostra classe mysql di essere chiamato in modo statico:

$username = Mysql::get_record("SELECT name FROM users WHERE id = '".$this->id."'"); 

http://php.net/manual/en/language.oop5.static.php

+0

Preferisco chiamarlo 'Mysql :: get_record (" SELECT name FROM users WHERE id =% d ", $ this-> id);' –

+0

Ci sono sicuramente molti miglioramenti che l'OP può apportare. La mia risposta affronta la stretta domanda di evitare incessanti istanze. – webbiedave

0

utilizzando le variabili globali, anche se non è probabilmente l'opzione migliore.

$mysql = new mysql(); 

function someFunction() { 
    global $mysql; 
    $mysql->get_record(...) 
} 

o un metodo statico per la classe mysql (vedi Singleton)

class mysql { 
    public static $theInstance = new mysql(); 
    public static function getInstance() { 
    return $this->theInstance; 
    } 
} 

function someFunction() { 
    $database= mysql::getInstance(); 
    $database->get_record(...) 
} 
+4

Uh, per favore non suggerire di usare globales! –

2

Questo è un problema comune, e quindi non è una soluzione comune a questo. Come forse saprai, nello sviluppo di software soluzioni comuni su problemi comuni sono chiamate Design Patterns.

Esistono due schemi di progettazione che possono aiutare a risolvere questo problema. In un senso più astratto il problema che si trovano ad affrontare è:

Come posso fare classe A disposizione in classe B?

Il pattern Singleton

"Nel pattern Singleton una classe può distribuire un'istanza di se stesso ad altre classi."

Questo non è esattamente quello che stai cercando, in quanto il tuo sito web potrebbe utilizzare più connessioni al database. Tuttavia, viene utilizzato da molte persone in questo modo.

leggere alcune informazioni su come utilizzare una classe Singleton come un provider di database qui: https://www.ibm.com/developerworks/library/os-php-designptrns/#N10124

Maggiori informazioni sul pattern Singleton in PHP: http://www.fluffycat.com/PHP-Design-Patterns/Singleton/

Un altro approccio ragionevole è il modello di registro:

Modello registro

È possibile f Ind informazioni sul modello di registro sul link sottostante, così come un'implementazione quasi identica che stai cercando: http://www.sitecrafting.com/blog/php-patterns-part/

Ancora più potente è una combinazione tra il singleton e il registro.

Buona fortuna e buon divertimento con OOP PHP!

+2

In realtà, il modello singleton, in questo caso particolare, non è realmente necessario, dopotutto, tutto ciò che non fa nulla con una connessione al database non ha bisogno di accedere a quella classe, e usando singleton, l'intera applicazione ottiene l'accesso a Singleton. Lo stesso vale per il registro, sebbene sia un'alternativa leggermente migliore.No, direi che un oggetto di interazione del database è un servizio e che i servizi possono essere assegnati agli oggetti che ne hanno bisogno, ad esempio utilizzando il modello di iniezione delle dipendenze. Vedi: http://martinfowler.com/articles/injection.html – fwielstra

+0

@ Cthulhu - Il commento sull'utilizzo del modello singleton non è necessario perché questo problema è corretto, tuttavia è una soluzione comunemente utilizzata per questo problema specifico. Personalmente, non ho molta familiarità con l'iniezione di dipendenza, ma grazie per averlo indicato. Lo esamineremo. –

+1

+1 per l'iniezione delle dipendenze ... rende i test delle unità molto più semplici se non si dispone di globali dappertutto, invece di iniettare ciò che è necessario nella classe. E sì, sia il registro che il singleton sono anche globali ... solo più mascherati. – kander

5

Per uno, non è necessario utilizzare singleton in questo caso - o in realtà, quasi mai. Vedere this article, ad esempio.

In secondo luogo, penso che i tuoi progetti OO siano un po 'spenti. Il punto principale della programmazione e della progettazione orientata agli oggetti è quello di isolare la responsabilità in classi separate. In questo momento, stai dando alla tua classe utente due principali responsabilità: memorizzare/trasportare i dati rilevanti di un utente e interrogare il servizio dati (in questo caso, un semplice livello di astrazione di database/MySQL).

È necessario spostare prima questa funzionalità in un oggetto separato. Di solito, questo è chiamato servizio - quindi in questo caso è un UserService. A UserService ha una sola responsabilità: fornire l'accesso agli oggetti User. Così che sarebbe sorta simile a questa:

class UserService { 
    public function __construct($mysql); // uses the mysql object to access the db. 
    public function get($id) { 
     $result = $this->mysql->get_record("select x from y"); 
     $user = new User($result['id'], $result['name']); // assuming user has a constructor that takes an id and a name 
     return $user; 
    } 
    public function save($user); 
    public function delete($user); 
} 

si legare tutto insieme all'inizio della vostra richiesta (o dove è necessario accedere gli utenti):

$mysql = new MySQL($credentials); 
$service = new UserService($mysql); 
$user = $service->find(1337); 

Non è perfetto, ma è un design molto più ordinato. Il tuo oggetto MySQL fa quello che deve fare (creare una connessione, eseguire query), il tuo oggetto utente è semplicemente stupido, e il tuo servizio fa solo una cosa, cioè fornire un livello tra il livello di archiviazione effettivo e la cosa che lo chiama.

+0

+1 Questo è un ottimo design! Gli oggetti utente dovrebbero avere una responsabilità, per contenere i dati dell'utente. –

+0

Questo è il modo migliore per farlo! Questo è davvero un buon consiglio. Ancora meglio sarebbe con l'uso dell'interfaccia, ma è abbastanza buono. Testabile, pulito. thumbs up –

+0

Ho cercato un modo semplice per spiegare il miglior metodo di comunicazione con un database. L'unica differenza tra gli approcci qui è che ho usato un controller invece della classe di servizio. Tuttavia, ora ho visto questo, penso di poter ancora utilizzare il mio controller e separare le funzionalità dal servizio. – Adsy2010

Problemi correlati