I have a "static" class which connects to database and has various functions. The current base layout is as follows:
class DB {
private static $con;
private function __construct() {};
private static function init() {
if(is_null(self::$con) {
// Initialize database connection
}
}
public static someMethod1() {
self::init();
// Do stuff
}
public static someMethod2() {
self::init();
// Do stuff
}
public static someMethod2() {
self::init();
// Do stuff
}
}
My intention is to be easily be able to call these methods as: DB::someMethod1(). However, as you can see, I am having to cehck for initialization at every method beginning. Is this a good coding practice? Is there a better design pattern available? Initially I thought of builder pattern but that doesn't really fit here in my opinion.
It looks like you are trying to ensure that there is a single instance of your DB class AND also that the instance is available as a single, globally available constant.
I'd recommend separating those two concerns in order to simplify the implementation.
First, I'd focus on getting the database access object right. Plain objects are simpler to test and inject as dependencies than static functions. For example,
class DBThing
{
private $con;
public static function build()
{
return new static('theconnection');
}
function __construct($con)
{
$this->con = $con;
}
public function someMethod1()
{
echo "someMethod1: $this->con\n";
}
public function someMethod2()
{
echo "someMethod2: $this->con\n";
}
public function someMethod3()
{
echo "someMethod3: $this->con\n";
}
}
Gives you an object you can easily test and replace with alternate implementations if needed.
Second, I'd focus on the object lifecycle and making it discoverable in the application.
If you're really OK with a single instance and the global state that implies, then something like this gets you close to the interface you asked for in your original post.
$DB = DBThing::build();
$DB->someMethod1();
$DB->someMethod2();
$DB->someMethod3();
In general, I discourage global state but I'd have to know more about your application to know if it's appropriate in your case.
I just wrote a simple db class for a coding test. Take a look at how I used here: https://github.com/TheRealJAG/Valuation-Vision-Full-Stack-Test/blob/master/classes/db.php
class DB
{
private static $instance = null;
private $db;
private $host = '';
private $username = '';
private $password = '';
private $database = '';
private function __construct()
{
$this->db = new mysqli($this->host, $this->username, $this->password, $this->database);
if ($this->db->connect_error) {
throw new Exception("Connection to the mysql database failed: " . $this->db->connect_error);
}
}
public static function connection()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance->db;
}
}
I'm 100% sold on the approach, but with the time I had for the test this is what I wrote. My biggest concern was that I only had 1 db connection open.
Related
I am building an API in PHP and I have a question. I'm using classes, and some of these classes need to access my database. However, I don't want to define variables for the database in every single class in order to open it, or have to send my mysqli object as a parameter of every single class constructor.
What would be the best way to go about this? Do I define a global variable of some kind?
A classic solution would be as follows
Create an instance of dbatabase handler class, either raw mysqli (worse) or better abstraction class (way better)
In the constructor of your application class take this db class instance as a parameter and assign it to a local variable
Use this variable with your class.
A quick example:
class Foo()
{
protected $db;
function __construct($db);
{
$this->db = $db;
}
function getBar($id)
{
return $this->db->getOne("SELECT * FROM bar WHERE id=?i", $id);
}
}
$db = new safeMysql();
$foo = new Foo($db);
$bar = $foo->getBar($_GET['id']);
How about using a static classes?
class mysqli_wrapper {
private static $db = null;
public static function open() {
GLOBAL $opts; // this can be global or setup in other ways
if (!self::$db) {
self::close();
self::$db = null;
}
self::$db = #mysqli_connect('p:'.$opts['hn'], $opts['un'], $opts['pw'], $opts['db']);
return self::$db;
}
public static function query($qry) {
return mysqli_query ( self::$db, $qry );
}
public static function affected_rows() { return #mysqli_affected_rows(self::$db); }
public static function error() { return #mysqli_error(self::$db); }
public static function close() { #mysqli_close(self::$db); }
} // end mysqli_wrapper
mysqli_wrapper::open(); // Here's how to call it
In a system I maintain my app needs to access its own MySQL db, as well as remote Oracle and SQL Server databases, and I use a trait for it. Here's a simplification of my code, just using MySQL:
dbaccess.php
trait DatabaseAccess {
protected $db;
private $host = 'host', $dbName = 'db', $username = 'username', $password = 'pword';
public function connectToMysql() {
$this->db= new mysqli(......);
}
}
then in myclass.php
require 'dbaccess.php';
class MyClass {
use DatabaseAccess;
//class code.....
}
All elements of DatabaseAccess will be available as if you hand-typed them in MyClass.
Note: if you're using PHP < 5.4, then this solution won't be possible.
Consider the following code below, I've been thought by Lynda.com
to create a database class like this, my question is why not create
a static method for the database entirely instead of storing an
instance into a static property?
<?php
class Database {
private $conn;
private static $init;
public function __construct() {
$this->conn = new mysqli('localhost','root','root','mydb');
}
public static function getInstance() {
self::$init = new self();
return self::$init;
}
}
$db = Database::getInstance();
?>
If you want to use singleton you should to protect __construct()
class DB
{
private static $instance;
private function __construct($args)
{
// do some
}
public static function getInstance()
{
// get instance
}
}
$query = 'SELECT etc...';
$stmt = DB::getInstance()->prepare($query);
I use this pattern in DB class. But if you have more than 1 connection you should NOT! use singleton.
My guess is that code you posted was intended to be the following because it looks like it was intended to be a singleton. I've only changed the getInstance() method.
class Database {
private $conn;
private static $init;
public function __construct() {
$this->conn = new mysqli('localhost','root','root','mydb');
}
public static function getInstance() {
if (is_null(self::$init)) {
self::$init = new self();
}
return self::$init;
}
}
$db = Database::getInstance();
I think this should clear up the confusion of why a static instance variable is used.
If this wasn't intended to be a singleton, then your question of "why didn't they just use a static method" should have the answer "they should have".
Just to clarify, $db is a Database object, which is instantiated by calling static method getInstance().
why not create a static method for the database entirely?
A static method is defined inside a class, however it can be called without having to instantiate the class. In other words, a static method belongs to the class, since in can be called without instantiating an object.
You can add methods to the Database class to interact with the database as you deem necessary.
I've trying to learn PHP OOP and have made some research on how to make a global database class to use around in my project. From what I've seen the most appropriate pattern available is a singleton which would ensure that only one database connection are present at all times. However as this is my first time working with the Singleton pattern, I am not sure that I have made it right.
Is this a proper singleton? Will this code ensure one database connection only? Is there any way I can test this? (Learn a man to fish and he will have food for the rest of his life...)
I am using redbean as my ORM and here's how I set it up plainly:
require_once PLUGINPATH.'rb.php';
$redbean= R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
I've made the following script based upon this source, as my own singleton Database class;
class database {
private $connection = null;
private function __construct(){
require_once PLUGINPATH.'rb.php';
$this->connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
static $db = null;
if ( $db === null )
$db = new database();
return $db;
}
public function connection() {
return $this->connection;
}
}
Thanks!
The instance variable needs to be a static member of the class. I haven't tested this code, but it should work. Connection should probably be static too. With this code, you will have one instance of your database class, and one instance of the connection. It is possible to do this without connection being static, but making it static will ensure there is only one connection instance. I also changed the literal names of the class to php magic constants. This make your code more maintainable. If you change the name of your class down the road, you won't have to go and find all of the literal instances of the old class name in your code. This may seem like overkill now, but trust me, as you work on more and more complex projects, you will appreciate the value.
class database {
private static $connection = null;
private static $db;
private function __construct(){
require_once PLUGINPATH.'rb.php';
self::$connection = R::setup("mysql:host=192.168.1.1;dbname=myDatabase",'username','password');
}
public static function get() {
if ( !(self::$db instanceof __CLASS__) ) {
$klass = __CLASS__; // have to set this to a var, cant use the constant with "new"
self::$db = new $klass();
}
return self::$db;
}
public function connection() {
return self::$connection;
}
}
You're singleton is almost correct.
The private member (no pun intended) $connection needs to be static as well. You might go with the following too:
class database {
private static $instance = NULL;
protected $conn;
private function __construct() {
$this->conn = mysql_connect( ... );
}
public static function init() {
if (NULL !== self::$instance)
throw new SingletonException();
self::$instance = new database();
}
public static function get_handle() {
if (NULL === self::$instance)
; // error handling here
return self::$instance->conn;
}
}
Should have asked someone this a long time ago.
What is the best way to use other classes within another class?
For instance, lets say I have an application class:
class Application
{
public function displayVar() {
echo 'hello world';
}
}
and a database class
class Database
{
// connects to db on construct
public function query() {
// queries db
}
}
now, i want to add a function to my application class that uses a function from the db class
class Application
{
public function displayVar() {
echo 'hello world';
}
public function getVar() {
global $db;
$sql = foo;
$db->query($sql);
}
}
so then I have
$db = new Database();
$app = new Application();
$app->getVar('var');
Is there a better way of doing this? Really what I am looking for is the standard way of doing it, not another way of rigging it.
There are a couple of ways of doing that. Global variables is certainly one way and the most looked down upon too. You can create a Singleton and all other classes that need database access would call upon this singleton.
final class Database {
private static $connection;
public static function getInstance() {
if(self::$connection == NULL) {
self::$connection = // init your database connection
}
return self::$connection;
}
}
And use this database connection object in whatever class needs it.
class Application {
public function displayVar() {
echo 'hello world';
}
public function getVar() {
$db = Database::getInstance();
$sql = foo;
$db->query($sql);
}
}
This is all well for a start and a great step beyond using global variables, but you can do better with Dependency Injection. Dependency Injection is a simple concept that if a class has any external dependencies, such as the database connection in your example, you explicitly pass those to the needy class in its constructor or a method. So the new code would look something like Jonathan's solution. A major advantage of using dependency injection is in unit testing, where you can easily replace this actual database object with a mock object and pass it to whoever needs it.
class Application {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
public function displayVar() {
echo 'hello world';
}
public function getVar() {
$sql = foo;
$this->db->query($sql);
}
}
For smaller projects, you can easily do it yourself. For large projects, there are various DI frameworks available for PHP
$db could be a property of your Application class. Any reference to it from within an instance of Application would be done via $this - $this->db
class Application {
private $db = null;
public function setDB($name) {
$this->db = new Database($name);
}
}
Include the class file (or set up autoinclude) in each PHP file that needs the class in question. Then instantiate it as needed.
If you need to have a "common" instance of an object, you can look at the Singleton and Factory patterns:
Singleton Pattern
Factory Pattern
I am going to use singleton classes to manage both DB connections and references to application settings.
It seems a little messy to have to use the following code in every method in order to access the db class.
$db = DB::getInstance();
Is there a more efficient way of going about it?
Any advice appreciated.
Thanks
I often use the Registry pattern, where this behavior occurs as well. I always set a instance variable in the constructor of my models to point to the Registry entry;
class Registry {
private static $_instance;
private $_registry;
private function __construct() {
$_registry = array();
}
public static function getInstance() {
if (!Registry::$_instance) {
Registry::$_instance = new Registry();
}
return Registry::$_instance;
}
public function add($key, &$entry) {
$this->_registry[$key] = &$entry;
}
public function &get($key) {
return $this->_registry[$key];
}
public function has($key) {
return ($this->get($key) !== null);
}
}
Model example;
class MyModel {
private $_db;
public function __construct() {
$this->_db = Registry::getInstance()->get('dbKey');
}
/* Every function has now access to the DAL */
}
Instantiation example;
$dal = new Db(...);
Registry::getInstance()->add('dbKey', $dal);
...
$model = new MyModel();
$model->doDbStuff();
Another approach is to always pass the reference as a parameter to each constructor.
Of course I only use this behavior when most of the methods in my model use the reference, if only a few (one or two) methods have use of the reference, I call the Registry/Singleton like you showed.
It is not messy. This is an intended behavior of Singletons. And, actually, this is just one line of code. Do you wish to make it even more compact? :)
My preferred method is to create a Base class which all the classes that need db access descend from. Base calls the singleton(s) in its constructor. All its children call their parent constructor. e.g.:
class Base {
protected $db;
public function __construct(){
$this->db = DB::getInstance();
}
}
class Achild extends Base {
protected $var1;
public function __construct($arg){
parent::__construct();
$this->var1=$arg;
}
}
I know what you mean... hate that ::getInstance() stuff! So go and use static methods:
class DB {
private static $db;
public static function getInstance() {
if(!self::$db) {
self::$db = new DBconnector();
}
}
public static function query($query) {
return self::$db->query($query);
}
}
Usage is much nicer:
$result = DB::query('SELECT whatever;');
And if you use PHP 5.3 you can write a __callStatic similar to this, to forward all the method calls to the object:
public static function __callStatic($method, $args) {
call_user_func_array(array(self::$db, $method), $args);
}
And to make me happy, add an __autoloader so that you can access DB without any worries any time!