Come posso evitare l'anti-pattern "global $ dbh"?

1

Questo è ciò che la maggior parte del mio codice di libreria relativo al database assomiglia a:

lib.php

<?php

$dbh = new PDO(...);

function doSomeDatabaseThing() {
    global $dbh;
    return $dbh->doStuff();
}

function doSomeOtherThing() {
    global $dbh;
    return $dbh->doSomeOtherStuff();
}

index.php

<html>
    <head>...</head>
    <body>
        <?php
        require_once('lib.php');
        echo doSomeDatabaseThing();
        ?>
    </body>
</html>

Continuo a leggere che i globals in PHP sono generalmente cattivi. Naturalmente, questo non significa che dovrei mai utilizzare globals, ma mi sembra sbagliato usare ripetutamente questo pattern in quasi tutti i codici di database che scrivo.

Quindi, come dovrei farlo senza i globals? Potrei provare qualcosa di simile

lib.php

$dbh = new PDO(...);
function doSomeDatabaseThing($dbh) { ... }

index.php

doSomeDatebaseThing($dbh);

ma sembra brutto scrivere " ($dbh) " ogni volta che chiamo una funzione di database.

C'è un modo migliore per risolvere questo?

    
posta Doorknob 16.11.2014 - 17:07
fonte

1 risposta

6

Progettazione orientata agli oggetti + Iniezione di dipendenza (DI)

Dovresti prendere in considerazione l'utilizzo del design orientato agli oggetti insieme al contenitore Iniezione di dipendenza . Raccomando Symfony in particolare perché ha un ottimo Componente contenitore DI .

Invece di avere un sacco di funzioni relative ai DB, considera di raggrupparle in classi che si occupano di particolari tipi di oggetti di dominio, in questo modo:

// repository interface
interface Repository
{
    public function findById($id);
}

// specific repository dealing with user objects
class UserRepository implements Repository
{
    private $dbh;

    function __construct(PDO $dbh)
    {
        $this->dbh = $dbh;
    }

    public function findById($id)
    {
        // just an example, should use at least prepared statement here
        $userRow = $this->dbh->query("...");
        // ...
        return $user;
    }
}

Invece di avere global $dbh ora inietti in costruttore di SomethingRepository come dipendenza , da cui il nome del modello. Si chiama iniezione del costruttore e ci sono altri tipi .

L'iniezione sta fondamentalmente istanziando tutte le dipendenze e passandole in costruttori / setter. Questo è ciò che fanno i contenitori DI. Fornisci una configurazione che descrive come gli oggetti dipendono l'uno dall'altro, il framework li costruisce.

Perché global $x considera anti-pattern?

  1. Il nome di $x può essere soggetto a modifiche = > tempo felice di ridenominazione
  2. Qualsiasi oggetto che utilizza $x può sovrascriverlo = > debugging delle ore felici
  3. Può causare problemi di sicurezza nel caso in cui hai attivato register_globals o se compresi i file di origine di terze parti = > tempo felice per affrontare gli attacchi degli hacker

Of course, this doesn't mean that I should never use globals

Questo significa che dovresti evitare di usare il costrutto global $x a tutti i costi. Puoi creare totalmente qualsiasi applicazione senza di essa, a meno che tu non sia bloccato con qualche codice legacy o versione preistorica di PHP.

    
risposta data 16.11.2014 - 21:48
fonte

Leggi altre domande sui tag