1

This is what most of my database-related library code looks like:

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>

I keep reading that globals in PHP are generally bad. Of course, this doesn't mean that I should never use globals, but it seems wrong to repeatedly use this pattern in almost all database code I write.

So, how should I do this without globals? I could try something like

lib.php

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

index.php

doSomeDatebaseThing($dbh);

but it looks ugly to have to write "($dbh)" every single time I call a database function.

Is there a better way to solve this?

  • Dependency Injection is beautiful. A hidden dependency inside your function/method is ugly, creepy and frustrating. IMO. – 53777A Nov 17 '14 at 8:28
6

Object-oriented design + Dependency Injection (DI)

You should consider using object-oriented design together with Dependency Injection container. I recommend Symfony specifically because it has a great DI container component.

Instead of having a bunch of DB-related functions, consider grouping them into classes which deal with particular types of domain objects, like so:

// 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;
    }
}

Instead of having global $dbh you now inject it into constructor of SomethingRepository as a dependency, hence the name of the pattern. That is called constructor injection, and there are other types.

Injection is basically instantiating all the dependencies and passing them into constructors/setters. That's what DI containers do. You provide a configuration describing how objects depend on each other, framework builds them.

Why is global $x considered anti-pattern?

  1. Name of $x can be a subject to change => happy time renaming
  2. Any object using $x can overwrite it => happy time debugging
  3. Can cause security issues in case you have register_globals enabled or if you including third-party source files => happy time dealing with hacker attacks

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

That means you should avoid using global $x construct at all costs. You can totally build any application without it, unless you stuck with some legacy code or prehistoric version of PHP.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.