I have a Database class for connecting to DB.
<?php
require_once('config.php');
class Database {
function __construct(){
$this->connect();
}
public function connect(){
$this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
}
}
?>
And a main class where I need to use the DB connection:
include 'includes/database.php';
class Main{
var $mysqli;
public function __construct(){
$this->mysqli = new Database();
}
But this is not working, since I get an error for queries that are still in the main classes, I intend to move them to the DB class later. But now I am getting an error:
Fatal error: Uncaught Error: Call to undefined method
Database::query() in /home/vagrant/Projects/MyProject/index.php
on line 262
Queries are done in the Main class:
$result = $this->mysqli->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
You are trying to call a query() method on the Database class. While that class contains a mysqli object in its $connection property, it does not expose the query() method of that mysqli object.
Given your current code, you could drill further into the object structure to call query() directly on the mysqli, but this is messy.
// Call the query() method directly on the connection
$result = $this->mysqli->connection->query( "SELECT shops.*, shops.id AS shop,SUM(price)...
I don't like this approach because it requires that your classes know more about the inner workings of the Database class than they probably should. It couples them too tightly.
As an alternative, you could create a query() method in the Database class that wraps the necessary functionality of the mysqli object within it.
class Database {
function __construct(){
$this->connect();
}
public function connect(){
$this->connection = mysqli_connect(SERVER, USERNAME, PASSWORD, DATABASE);
}
// Expose a query() method that calles the inner mysqli's query
public function query($sql) {
return $this->connection->query($sql);
}
}
This would allow you to pack in more functionality, such as querying and fetching all result rows in one method call:
class Database {
//....
// A more featured query() that returns the
// rows as an array
public function query($sql) {
$result = $this->connection->query($sql);
while ($row = $result->fetch_assoc()) {
$rows[] = $row;
}
// Return an array of all the rows fetched from the query
return $rows;
}
}
If you do it this way, you should be able to call $this->mysqli->query("...") as you originally attempted and either get back the result resource with the simple version, after which you must fetch in the code yourself, or get back an array of associative result rows in the more featured version.
Creating these kinds of database wrapper classes can get unwieldy rather quickly though. Think carefully about what aspects of the mysqli object you want to expose to the other classes in your application. It's not a good idea to go down a path of wrapping every mysqli method in your Database class. At that point, the utility of the Database class is greatly reduced and you may as well just be passing in a mysqli object directly. If you are not actively adding functionality to mysqli, it makes less sense to create another class that wraps it.
A note about the var $mysqli;... This is an old deprecated class property syntax. The var keyword is a vestige from PHP4 and its use is discouraged nowadays. In fact, it has been removed from recent PHP versions. Instead, you should declare it via the PHP5+ syntax:
// Declare as a public property
public $mysqli;
// Or better, as a private (or protected) property so it cannot
// be accessed outside the Main class' own methods
private $mysqli;
In your question title, you mentioned injection. Your class doesn't do that right now, but it would be a good idea to instantiate a Database ahead of time and inject one into the class constructors that need it.
class Main{
public $mysqli;
// Pass a database as a constructor param
public function __construct($database){
$this->mysqli = $database;
}
Then instantiate it as:
$db = new Database();
// Pass the $db to the other classes
$main = new Main($db);
Importantly, this will prevent you from opening up a separate database connection for each object you instantiate of Main and any other class you construct in the same way. Doing that can quickly use up the server's available MySQL connections.
I've a simple application, say it has some classes and an "extra" one that handles database requests. Currently i'm creating the database object everytime the app is used, but in some cases there's no need for a database connection. I'm doing it like this (PHP btw):
$db = new Database();
$foo = new Foo($db); // passing the db
But sometimes the $foo object does not need db access, as only methods without database actions are called. So my question is: What's the professional way to handle situations like this / how to create the db connection/object only when needed ?
My goal is to avoid unnecessary database connections.
Note: Although the direct answer to ops question, "when can I only create / connect to the database when required and not on every request" is inject it when you need it, simply saying that is not helpful. I'm explaining here how you actually go about that correctly, as there really isn't a lot of useful information out there in a non-specific-framework context to help in this regard.
Updated: The 'old' answer to this question can be see below. This encouraged the service locator pattern which is very controversial and to many an 'anti-pattern'. New answer added with what I've learned from researching. Please read the old answer first to see how this progressed.
New Answer
After using pimple for a while, I learned much about how it works, and how it's not actually that amazing after all. It's still pretty cool, but the reason it's only 80 lines of code is because it basically allows the creation of an array of closures. Pimple is used a lot as a service locator (because it's so limited in what it can actually do), and this is an "anti-pattern".
Firstly, what is a service locator?
The service locator pattern is a design pattern used in software development to encapsulate the processes involved in obtaining a service with a strong abstraction layer. This pattern uses a central registry known as the "service locator" which on request returns the information necessary to perform a certain task.
I was creating pimple in the bootstrap, defining dependencies, and then passing this container to each and every single class I instantiated.
Why is a service locator bad?
What's the problem with this you say? The main problem is that this approach hides dependencies from the class. So if a developer is coming to update this class and they haven't seen it before, they're going to see a container object containing an unknown amount of objects. Also, testing this class is going to be a bit of a nightmare.
Why did I do this originally? Because I thought that after the controller is where you start doing your dependency injection. This is wrong. You start it straight away at the controller level.
If this is how things work in my application:
Front Controller --> Bootstrap --> Router --> Controller/Method --> Model [Services|Domain Objects|Mappers] --> Controller --> View --> Template
...then the dependency injection container should start working right away at the first controller level.
So really, if I were to still use pimple, I would be defining what controllers are going to be created, and what they need. So you would inject the view and anything from the model layer into the controller so it can use it. This is Inversion Of Control and makes testing much easier. From the Aurn wiki, (which I'll talk about soon):
In real life you wouldn't build a house by transporting the entire hardware store (hopefully) to the construction site so you can access any parts you need. Instead, the foreman (__construct()) asks for the specific parts that will be needed (Door and Window) and goes about procuring them. Your objects should function in the same way; they should ask only for the specific dependencies required to do their jobs. Giving the House access to the entire hardware store is at best poor OOP style and at worst a maintainability nightmare. - From the Auryn Wiki
Enter Auryn
On that note, I'd like to introduce you to something brilliant called Auryn, written by Rdlowrey that I was introduced to over the weekend.
Auryn 'auto-wires' class dependencies based on the class constructor signature. What this means that, for each class requested, Auryn finds it, figures out what it needs in the constructor, creates what it needs first and then creates an instance of the class you asked for originally. Here's how it works:
The Provider recursively instantiates class dependencies based on the parameter type-hints specified in their constructor method signatures.
...and if you know anything about PHP's reflection, you'll know some people call it 'slow'. So here's what Auryn does about that:
You may have heard that "reflection is slow". Let's clear something up: anything can be "too slow" if you're doing it wrong. Reflection is an order of magnitude faster than disk access and several orders of magnitude faster than retrieving information (for example) from a remote database. Additionally, each reflection offers the opportunity to cache the results if you're worried about speed. Auryn caches any reflections it generates to minimize the potential performance impact.
So now we've skipped the "reflection is slow" argument, here's how I've been using it.
How I use Auryn
I make Auryn part of my autoloader. This is so that when a class is asked for, Auryn can go away and read the class and it's dependencies, and it's dependencies' dependencies (etc), and return them all into the class for instantiation. I create the Auyrn object.
$injector = new \Auryn\Provider(new \Auryn\ReflectionPool);
I use a Database Interface as a requirement in the constructor of my database class. So I tell Auryn which concrete implementation to use (this is the part you change if you want to instantiate a different type of database, at a single point in your code, and it'll all still work).
$injector->alias('Library\Database\DatabaseInterface', 'Library\Database\MySQL');
If I wanted to change to MongoDB and I'd written a class for it, I'd simple change Library\Database\MySQL to Library\Database\MongoDB.
Then, I pass the $injector into my router, and when creating the controller / method, this is where the dependencies are automatically resolved.
public function dispatch($injector)
{
// Make sure file / controller exists
// Make sure method called exists
// etc...
// Create the controller with it's required dependencies
$class = $injector->make($controller);
// Call the method (action) in the controller
$class->$action();
}
Finally, answer OP's question
Okay, so using this technique, let's say you have the User controller which requires the User Service (let's say UserModel) which requires Database access.
class UserController
{
protected $userModel;
public function __construct(Model\UserModel $userModel)
{
$this->userModel = $userModel;
}
}
class UserModel
{
protected $db;
public function __construct(Library\DatabaseInterface $db)
{
$this->db = $db;
}
}
If you use the code in the router, Auryn will do the following:
Create the Library\DatabaseInterface, using MySQL as the concrete class (alias'd in the boostrap)
Create the 'UserModel' with the previously created Database injected into it
Create the UserController with the previously created UserModel injected into it
That's the recursion right there, and this is the 'auto-wiring' I was talking about earlier. And this solves OPs problem, because only when the class hierarchy contains the database object as a constructor requirement is the object insantiated, not upon every request.
Also, each class has exactly the requirements they need to function in the constructor, so there are no hidden dependencies like there were with the service locator pattern.
RE: How to make it so that the connect method is called when required. This is really simple.
Make sure that in the constructor of your Database class, you don't instantiate the object, you just pass in it's settings (host, dbname, user, password).
Have a connect method which actually performs the new PDO() object, using the classes' settings.
class MySQL implements DatabaseInterface
{
private $host;
// ...
public function __construct($host, $db, $user, $pass)
{
$this->host = $host;
// etc
}
public function connect()
{
// Return new PDO object with $this->host, $this->db etc
}
}
So now, every class you pass the database to will have this object, but will not have the connection yet because connect() hasn't been called.
In the relevant model which has access to the Database class, you call $this->db->connect(); and then continue with what you want to do.
In essence, you still pass your database object to the classes that require it, using the methods I have described previously, but to decide when to perform the connection on a method-by-method basis, you just run the connect method in the required one. No you don't need a singleton. You just tell it when to connect when you want it to, and it doesn't when you don't tell it to connect.
Old Answer
I'm going to explain a little more in-depth about Dependency Injection Containers, and how they can may help your situation. Note: Understanding the principles of 'MVC' will help significantly here.
The Problem
You want to create some objects, but only certain ones need access to the database. What you're currently doing is creating the database object on each request, which is totally unnecessary, and also totally common before using things like DiC containers.
Two Example Objects
Here's an example of two objects that you may want to create. One needs database access, another doesn't need database access.
/**
* #note: This class requires database access
*/
class User
{
private $database;
// Note you require the *interface* here, so that the database type
// can be switched in the container and this will still work :)
public function __construct(DatabaseInterface $database)
{
$this->database = $database;
}
}
/**
* #note This class doesn't require database access
*/
class Logger
{
// It doesn't matter what this one does, it just doesn't need DB access
public function __construct() { }
}
So, what's the best way to create these objects and handle their relevant dependencies, and also pass in a database object only to the relevant class? Well, lucky for us, these two work together in harmony when using a Dependency Injection Container.
Enter Pimple
Pimple is a really cool dependency injection container (by the makers of the Symfony2 framework) that utilises PHP 5.3+'s closures.
The way that pimple does it is really cool - the object you want isn't instantiated until you ask for it directly. So you can set up a load of new objects, but until you ask for them, they aren't created!
Here's a really simple pimple example, that you create in your boostrap:
// Create the container
$container = new Pimple();
// Create the database - note this isn't *actually* created until you call for it
$container['datastore'] = function() {
return new Database('host','db','user','pass');
};
Then, you add your User object and your Logger object here.
// Create user object with database requirement
// See how we're passing on the container, so we can use $container['datastore']?
$container['User'] = function($container) {
return new User($container['datastore']);
};
// And your logger that doesn't need anything
$container['Logger'] = function() {
return new Logger();
};
Awesome! So.. how do I actually use the $container object?
Good question! So you've already created the $container object in your bootstrap and set up the objects and their required dependencies. In your routing mechanism, you pass the container to your controller.
Note: example rudimentary code
router->route('controller', 'method', $container);
In your controller, you access the $container parameter passed in, and when you ask for the user object from it, you get back a new User object (factory-style), with the database object already injected!
class HomeController extends Controller
{
/**
* I'm guessing 'index' is your default action called
*
* #route /home/index
* #note Dependant on .htaccess / routing mechanism
*/
public function index($container)
{
// So, I want a new User object with database access
$user = $container['User'];
// Say whaaat?! That's it? .. Yep. That's it.
}
}
What you've solved
So, you've now killed multiple birds (not just two) with one stone.
Creating a DB object on each request - Not any more! It's only created when you ask for it because of the closures Pimple uses
Removing 'new' keywords from your controller - Yep, that's right. You've handed this responsibility over to the container.
Note: Before I continue, I want to point out how significant bullet point two is. Without this container, let's say you created 50 user objects throughout your application. Then one day, you want to add a new parameter. OMG - you now need to go through your whole application and add this parameter to every new User(). However, with the DiC - if you're using $container['user'] everywhere, you just add this third param to the container once, and that's it. Yes, that totally is awesome.
The ability to switch out databases - You heard me, the whole point of this is that if you wanted to change from MySQL to PostgreSQL - you change the code in your container to return a new different type of database you've coded, and as long as it all returns the same sort of stuff, that's it! The ability to swap out concrete implementations that everyone always harps on about.
The Important Part
This is one way of using the container, and it's just a start. There are many ways to make this better - for example, instead of handing the container over to every method, you could use reflection / some sort of mapping to decide what parts of the container are required. Automate this and you're golden.
I hope you found this useful. The way I've done it here has at least cut significant amounts of development time for me, and it's good fun to boot!
This is approximately what I use.
class Database {
protected static $connection;
// this could be public if you wanted to be able to get at the core database
// set the class variable if it hasn't been done and return it
protected function getConnection(){
if (!isset(self::$connection)){
self::$connection = new mysqli($args);
}
return self::$connection;
}
// proxy property get to contained object
public function __get($property){
return $this->getConnection()->__get($property);
}
// proxy property set to contained object
public function __set($property, $value){
$this->getConnection()->__set($property, $value);
}
// proxy method calls to the contained object
public function __call($method, $args){
return call_user_func_array(array($this->getConnection(), $method), $args);
}
// proxy static method calls to the contained object
public function __callStatic($method, $args){
$connClass = get_class($this->getConnection());
return call_user_func_array(array($connClass, $method), $args);
}
}
Note it only works if there is a single database in play. If you wanted multiple different databases it would be possible to extend this but beware of late static binding in the getConnection method.
Here is an example of a simple approach:
class Database {
public $connection = null ;
public function __construct($autosetup = false){
if ($autosetup){
$this->setConnection() ;
}
}
public function getProducts(){//Move it to another class if you wish
$this->query($sql_to_get_products);
}
public function query($sql) {
if (!$connection || !$connection->ping()){
$this->setupConnection() ;
}
return $this->connection->query($sql);
}
public function setConnection(){
$this->connection = new MySQLi($a, $b, $c, $d) ;
}
public function connectionAvailable(){
return ($connection && $connection->ping()) ;
}
}
Look into using a dependency injection container, something like Pimple would be nice place to start. With a dependency injection container you 'teach' the container how to create the objects in your application, they're not instantiated until you ask for them. With Pimple, you can configure a resource to be shared so that it's only ever instantiated once during the request no matter how often you ask the container for it.
You can setup your classes to accept the container in their constructor or use a setter method to inject into your class.
A simplified example could look like this:
<?php
// somewhere in your application bootstrap
$container = new Pimple();
$container['db'] = $container->share(
function ($c) {
return new Database();
}
);
// somewhere else in your application
$foo = new Foo($container);
// somewhere in the Foo class definition
$bar = $this->container['db']->getBars();
Hope it helps.
You got some great answers already, with the majority concentrating on the aspect of injecting dependencies (which is a good thing), and only creating objects on demand.
The other aspect is the more important one: Do not put code that does any heavy work into your constructors. In case of a database object, this means: Do not connect to the database inside the constructor.
Why is this more important? Because not creating a database object because the using object also gets not created is no real optimization if the using object gets always created, but does not always run queries.
Creating an object in PHP is reasonable fast. The class code usually is available in the opcode cache, so it only triggers a call to the autoloader and then allocates some bytes in memory for the objects' properties. The constructor will run after that. If the only thing it does is copying the constructor parameters to local property variables, this is even optimized by PHP with "copy-on-write" references. So there is no real benefit if this object does not get created in the first place, if you cannot avoid it. If you can: even better.
I come from the world of Java. Java is resident in memory accross stateless HTML requests. PHP is not. That is a whole different story - and what I like about PHP.
I simply use:
$conn = #pg_connect(DBConnection);
the DBConnection is a definition containing the information about the host etc..
The # assures that the current connection is used or a new one is created. How can I do it more easily?
The data how to connect to the database is stable. The connection itself might be recreated during a request. Why should I program better then the people of PHP and recreate the #? They did that for the PHP community, let's use it.
By the way, never put heavy objects in a constructor and never let the constructor do some heavy job nor let it happen that an exception can be thrown during construction of an object. You might have an unfinished object resident in your memory. An init-method is to be preferred. I agree on that with Henrique Barcelos.
This is the way I am using mysqli. Database object behaves the same as mysqli object, can add my own methods or override existing ones, and the only difference is that the actual connection to database is not established when you create the object but on first call to method or property that needs the connection.
class Database {
private $arguments = array();
private $link = null;
public function __construct() {
$this->arguments = func_get_args();
}
public function __call( $method, $arguments ) {
return call_user_func_array( array( $this->link(), $method ), $arguments );
}
public function __get( $property ) {
return $this->link()->$property;
}
public function __set( $property, $value ){
$this->link()->$property = $value;
}
private function connect() {
$this->link = call_user_func_array( 'mysqli_connect', $this->arguments );
}
private function link() {
if ( $this->link === null ) $this->connect();
return $this->link;
}
}
Another way to achieve the same behavior is with use of mysqli_init() and mysqli_real_connect() methods, constructor initializes the object with mysqli_init(), and when you need a real connection the mysqli_real_connect() method is used.
class Database {
private $arguments = array();
public function __construct() {
$this->arguments = array_merge( array( 'link' => mysqli_init() ), func_get_args() );
}
public function __call( $method, $arguments ) {
return call_user_func_array( array( $this->link(), $method ), $arguments );
}
public function __get( $property ) {
return $this->link()->$property;
}
public function __set( $property, $value ) {
$this->link()->$property = $value;
}
private function connect() {
call_user_func_array( 'mysqli_real_connect', $this->arguments );
}
private function link() {
if ( !#$this->arguments['link']->thread_id ) $this->connect();
return $this->arguments['link'];
}
}
I tested memory consumption for both approaches and got quite unexpected results, the second approach uses less resources when connects to database and executes queries.
interface IDatabase {
function connect();
}
class Database implements IDatabase
{
private $db_type;
private $db_host;
private $db_name;
private $db_user;
private $db_pass;
private $connection = null;
public function __construct($db_type, $db_host, $db_name, $db_user, $db_pass)
{
$this->db_type = $db_type;
$this->db_host = $db_host;
$this->db_name = $db_name;
$this->db_user = $db_user;
$this->db_pass = $db_pass;
}
public function connect()
{
if ($this->connection === null) {
try {
$this->connection = new PDO($this->db_type.':host='.$this->db_host.';dbname='.$this->db_name, $this->db_user, $this->db_pass);
$this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $this->connection;
} catch (PDOException $e) {
return $e;
}
} else {
return $this->connection;
}
}
}
How about this? In connect(), check if a connection has already been established, if yes, return it, if not, create it and return it. This will prevent you from having TOO many connections open. Let's say, in your controller action, you want to call two methods of UserRepository (that depends on the Database), getUsers() and getBlockedUsers(), if you call these methods, connect() will be called in each one of them, with this check in place it will return the already existing instance.
You could use an singleton pattern to achive this and request everytime you need the database a database object. This results in something like this
$db = DB::instance();
where DB::instance is declared something like this
class DB {
//...
private static $instance;
public static function instance() {
if (self::$instance == null) {
self::$instance = new self();
}
}
//...
}
<?php
mysql_select_db('foo',mysql_connect('localhost','root',''))or die(mysql_error());
session_start();
function antiinjection($data)
{
$filter_sql = stripcslashes(strip_tags(htmlspecialchars($data,ENT_QUOTES)));
return $filter_sql;
}
$username = antiinjection($_POST['username']);
$password = antiinjection($_POST['password']);
/* student */
$query = "SELECT * FROM student WHERE username='$username' AND password='$password'";
$result = mysql_query($query)or die(mysql_error());
$row = mysql_fetch_array($result);
$num_row = mysql_num_rows($result);
/* teacher */
$query_teacher = mysql_query("SELECT * FROM teacher WHERE username='$username' AND password='$password'")or die(mysql_error());
$num_row_teacher = mysql_num_rows($query_teacher);
$row_teahcer = mysql_fetch_array($query_teacher);
if( $num_row > 0 ) {
$_SESSION['id']=$row['student_id'];
echo 'true_student';
}else if ($num_row_teacher > 0){
$_SESSION['id']=$row_teahcer['teacher_id'];
echo 'true';
}else{
echo 'false';
}
?>
and in the php file insert javascript
<script>
jQuery(document).ready(function(){
jQuery("#login_form1").submit(function(e){
e.preventDefault();
var formData = jQuery(this).serialize();
$.ajax({
type: "POST",
url: "login.php",
data: formData,
success: function(html){
if(html=='true')
{
window.location = 'folder_a/index.php';
}else if (html == 'true_student'){
window.location = 'folder_b/index.php';
}else
{
{ header: 'Login Failed' };
}
}
});
return false;
});
});
</script>
another connection
<?php
class DbConnector {
var $theQuery;
var $link;
function DbConnector(){
// Get the main settings from the array we just loaded
$host = 'localhost';
$db = 'db_lms1';
$user = 'root';
$pass = '';
// Connect to the database
$this->link = mysql_connect($host, $user, $pass);
mysql_select_db($db);
register_shutdown_function(array(&$this, 'close'));
}
//*** Function: query, Purpose: Execute a database query ***
function query($query) {
$this->theQuery = $query;
return mysql_query($query, $this->link);
}
//*** Function: fetchArray, Purpose: Get array of query results ***
function fetchArray($result) {
return mysql_fetch_array($result);
}
//*** Function: close, Purpose: Close the connection ***
function close() {
mysql_close($this->link);
}
}
?>
I'm trying to create a pagination class and use a variable from outside the class.
But it's giving me the fatal error "Call to a member function query() on a non-object".
This is the index file:
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new pagi();
$records = $pagination->get_records("SELECT * FROM `table`");
And this is the pagi.php file:
class pagi {
public function get_records($q) {
$x = $db->query($q);
return $db->fetch($x);
}
}
Is it possible to use this variable from out side of the class inside the class, without creating a new one inside the class?
The correct way to solve this would be to inject the database object into the other class (dependency injection):
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator($db);
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`");
class Paginator
{
protected $db;
// Might be better to use some generic db interface as typehint when available
public function __construct(DB_MySQL $db)
{
$this->db = $db;
}
public function get_records($q) {
$x = $this->db->query($q);
return $this->db->fetch($x);
}
}
Another way you could solve it is by injecting the instance of the database class into the method that uses it:
$db = new DB_MySQL("localhost", "root", "", "test"); // connect to the database
include_once("pagi.php");
$pagination = new Paginator();
$records = $pagination->get_records("SELECT the, fields, you, want, to retrieve FROM `table`", $db);
class Paginator
{
public function get_records($q, DB_MySQL $db) {
$x = $db->query($q);
return $db->fetch($x);
}
}
Whichever method you choose depends on the situation. If only one method needs an instance of the database you can just inject it into the method, otherwise I would inject it into the constructor of the class.
Also note that I have renamed your class from pagi to Paginator. Paginator is a better name IMHO for the class because it is clear for other people (re)viewing your code. Also note that I have made the first letter uppercase.
Another thing I have done is changed the query to select the fields you are using instead of using the "wildcard" *. This is for the same reason I have changed the classname: People (re)viewing your code will know exactly what fields will be retrieved without checking the database and/or the result.
Update
Because answer gave rise to a discussion regarding why I would go the dependency injection route instead of declaring the object global, I would like to clarify why I would use dependency injection over the global keyword: When you have a method like:
function get_records($q) {
global $db;
$x = $db->query($q);
return $db->fetch($x);
}
When you are using the above method somewhere it isn't clear that the class or method uses depends on $db. Hence it is a hidden dependency. Another reason why the above is bad is because you have tightly coupled the $db instance (thus the DB_MySQL) class to that method / class. What if you need to use 2 databases at some point. Now you would have to go through all code to change global $db to global $db2. You should never need to change your code just to switch to another database. For this reason, you should not do:
function get_records($q) {
$db = new DB_MySQL("localhost", "root", "", "test");
$x = $db->query($q);
return $db->fetch($x);
}
Again, this is a hidden dependency, and tightly couples the DB_MySQL class to the method / class. Because of this it is also impossible to properly unit test the Paginator class. Instead of testing only the unit (the Paginator class) you are also testing the DB_MySQL class at the same time. And what if you have multiple tightly coupled dependencies? Now you are suddenly testing several classes with your so called unit tests. So when using dependency injection you can easily switch to another database class, or even a mocked one for testing purposes. Besides the benefit of testing only one unit (you don't have to worry about getting wrong results because of dependencies) it will also make sure your tests will finish fast.
Some people may think the Singleton pattern is the correct way to get access to a database object, but it should be clear, having read all of the above, a singleton is basically just another way of making things global. It might look different, but it has the exact same characteristics and hence the same problems as global.
Although I do agree that the dependency model is nice, for the database, I personally use a static connection that is available to all instances of the database class and the create instances to query whenever I need one. Here is an example:
<?php
//define a database class
class DB {
//the static connection.
//This is available to all instances of the class as the same connection.
private static $_conn;
//store the result available to all methods
private $result;
//store the last query available to all methods
private $lastQuery;
//static connection function. connects to the database and stores that connection statically.
public static function connect($host, $user, $pass, $db){
self::$_conn = mysqli_connect($host, $user, $pass, $db);
}
//standard function for doing queries. uses the static connnection property.
public function query($query){
$this->lastQuery = $query;
$this->result = mysqli_query(self::$_conn, $query);
//process result, return expected output.
}
}
//create connection to the database, this connection will be used in all instances of DB class
DB::connect('local', 'DB_USER', 'DB_PASS');
//create instance to query
$test = new DB;
//do query
$test->query("SELECT * FROM TABLE");
//test function
function foo(){
//create instance to use in this function
$bar = new DB;
//do query
$bar->query("SELECT * FROM OTHER_TABLE");
//return results
return $bar->fetchArray();
}
That way I can create all the instances I want of DB within any function, method...etc and use that local instance of the class to do all my queries. All instances use the same connection.
One thing to note though is that this only allows for one connection to the database per defined class but I only use one so this isn't an issue for me.
you could add the db-connection ($db) to the call of the get_records method:
Here are only the relevant lines of code:
First file:
$records = $pagination->get_records("SELECT * FROM `table`", $db);
Second file:
public function get_records($q, $db) {
The other answers thus far are definitely preferable to using a global since that will ruin your encapsulation (eg you'd need to have that object defined prior to calling that method).
It's much better to enforce that in the method signature or not use a class.
I am currently using PHPUnit and DBUnit for my project. I have a problem in DBUnit because DBUnit PHPUnit_Extensions_Database_TestCaseSrc class does not seem to be truncating the existing data on the test db. So this makes my insertion tests fail after only working for one time.
I am using mysql and here is my code :
abstract class Generic_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
// only instantiate pdo once for test clean-up/fixture load
static private $pdo = null;
// only instantiate PHPUnit_Extensions_Database_DB_IDatabaseConnection once per test
private $conn = null;
final public function getConnection()
{
if ($this->conn === null) {
if (self::$pdo == null) {
self::$pdo = new PDO( "mysql:dbname=db;host=localhost", "root", "pass" );
}
$this->conn = $this->createDefaultDBConnection(self::$pdo, "db");
}
return $this->conn;
}
}
class DbopTest extends Generic_Tests_DatabaseTestCase
{
private $db;
protected function setup(){
$this->db = null;
}
public function getDataSet(){
return $this->createMySQLXMLDataSet(dirname(__FILE__) . '/../rows.xml');
}
...
}
So how can I fix this problem? What is it that I do wrong here?
If you override the setUp method, PHPUnit won't automatically call your getDataSet method. You need to take care that you call the parent::setUp method as well, otherwise PHPUnit does not know what to do ;).
I came across this issue myself and this is how I resolved it after a bit of digging into the PHPUnit sourcecode. It looks like the default behavior for the PHPUnit_Extensions_Database_TestCase class is to return PHPUnit_Extensions_Database_Operation_Factory::NONE(). For what you need, and how the PHPUnit document seems to imply how it's supposed to work, you'll want to override the method to return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE().
Luckily, this is fairly straight-forward. You just need to add the following to your TestCase class.
protected function getTearDownOperation()
{
return \PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
Before this I was manually truncating tables in my Teardown() method, but I think you'll agree that this solution is much better.
Not expecting many too kudos for this answer, but I have spent several hours trying to figure out why one of my test database tables was not getting truncated, causing the same duplicate entry error described above. My getDataSet() looked like
function getDataSet() {
$files = array('languages','interpreters','interp_languages',
'interp_events','deft_events',
//etc
);
$dataSets = array();
foreach ($files as $file) {
$dataSets[] = new PHPUnit_Extensions_Database_DataSet_MysqlXmlDataSet(
$this->files_dir."/$file.xml");
}
return new PHPUnit_Extensions_Database_DataSet_CompositeDataSet($dataSets);
}
and the technique was working fine on other test classes. It happens that I inadvertentely left out one of my xml data file names from $files, therefore DbUnit was not loading that data file, ergo not truncating the table. But because there were plenty of rows left over in the table from other tests that were using that same data file, it was not obvious (to me) what was happening.
Hope it saves someone else from tearing her/his eyeballs out some day.
You need to have a getDataSet() method otherwise PHPUnit assumes you have no data to fixturize.
http://www.phpunit.de/manual/3.6/en/database.html
The getDataSet() method defines how the initial state of the database should look before each test is executed. The state of a database is abstracted through the concepts DataSet and DataTable both being represented by the interfaces PHPUnit_Extensions_Database_DataSet_IDataSet and PHPUnit_Extensions_Database_DataSet_IDataTable. The next section will describe in detail how these concepts work and what the benefits are for using them in database testing.
For the implementation we only need to know that the getDataSet() method is called once during setUp() to retrieve the fixture data-set and insert it into the database. In the example we are using a factory method createFlatXMLDataSet($filename) that represents a data-set through an XML representation.