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 likelib.php$dbh = new PDO(...);function doSomeDatabaseThing($dbh) { ... }index.phpdoSomeDatebaseThing($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?
How can I avoid the global $dbh anti-pattern?
php;anti patterns;globals
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 interfaceinterface Repository{    public function findById($id);}// specific repository dealing with user objectsclass 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?Name of $x can be a subject to change => happy time renamingAny object using $x can overwrite it => happy time debuggingCan cause security issues in case you have register_globals enabled or if you including third-party source files => happy time dealing with hacker attacksOf course, this doesn't mean that I should never use globalsThat 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.