It's quite common to implement the database connection as a singleton, which is essentially a static property in a class with a method which instantiates and/or returns the object depending on whether it has previously been instantiated. The downside is you end up having to make static calls to get at the database, which leads to a strong coupling between the two classes, and is just not very 'OO'.
The alternative is just to pass the connection to the method which needs it as a parameter. This might even be preferable as it removes the dependency between the class containing the getUserByID() method and the database connection. This can be a big help when unit testing a class.
Now you might think it can be annoying having to pass lots of parameters around which various objects needed, for example database connections and configuration, so a solution is the Service Locator pattern. This is essentially an object containing a bunch of factory methods for getting at common services needed by the app. You now just need to pass the Service Locator around.
A quick code example
class UserModel
{
function __construct( $servicelocator )
{
$this->servicelocator = $servicelocator
}
function getUserById( $id )
{
$row = $this->servicelocator->getDb()->query( 'SELECT ... WHERE ' . $id );
return $this->doSomethingWithRow( $row );
}
}
class SomeSpecificDatabase
{
function query( $sql )
{
// do query
}
}
class ServiceLocator
{
private static $instances = array();
function getDb()
{
if( !isset( ServiceLocator::$instances['db'] ))
{
ServiceLocator::$instances[$db] = new SomeSpecificDatabase;
}
return ServiceLocator::$instances[$db];
}
}
$service = new ServiceLocator;
$model = new UserModel( $service );
$user = $model->findUserById( 1 );
Dependencies still exist in the Service Locator but from a testing perspective thats better than having them littered throughout your code.
Sorry for the long post 😉