I am switching my MVC to use PDO (I know, overdue). My application has, in the past, used the following class hierarchy:
Database.class>Main.class>User.class
(each one extending the other). But before any object is created, the mysql connection was made (mysql_connect). Once the connection was open I could use Database.class as a wrapper class through which all my queries were performed. Through extention, a query in the User.class could be made simply by calling the "query" function ($this->query).
Using PDO, I've tried to imitate the process but find errors. I created a singleton function in the Database.class:
function __construct()
{
$this->db = new PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8', DB_USER, DB_PASSWORD);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
public static function getInstance()
{
if (!isset(self::$instance)){
$object = __CLASS__;
self::$instance = new $object;
}
return self::$instance;
}
function query($qry,$params=NULL){
$qry = $this->db->prepare('SELECT * FROM users WHERE userID = :userID');
$qry->execute(array(':userID' => 1));
$results = $qry->fetchAll(PDO::FETCH_ASSOC);
return $results;
}
Then in Main.class I get the instance:
function __construct()
{
$this->db = parent::getInstance();
}
So in User.class I try to call
function __construct(){
parent::__construct();
}
function test(){
return $this->db->query("test");
}
So I can run any queries fine from the Main.class object. But if I try to run queries from User.class object I get the error: "Call to a member function query() on a non-object" In other words, if User.class extends main I should be able to access the variable $db in Main from User.class (I call the constructor for Main when the User object is created). Part of the issue is that Main.class is created earlier in the application as it's own object, I believe causing two instances of PDO to be created - which is why it doesn't work through extension (through a second object that also extends the database.class)
So my question is: is there a way to make this happen? Or is my best option to use injection for every object I create (because some scripts incorporate multiple objects that extend Main.class - which try to create an instance of PDO each time) and pass the pdo object to the constructor? I'd rather not have to do that (the less markup the better) So another option would be to use a STATIC variable that all classes use? What's the best method? (let me know if this is confusing)
I've seen people using injection for this, and I've seen examples of extending the pdo wrapper class (but only once).
Thanks! (I love stack overflow!)
You dont want any of these to extend the database class because that will essentially make them all singletons of which you can only have one instance... you Want to make them USE the database class instead. So you would put you most abstract db methods on the Database and then methods that create queries for specific things would be on the User or what have you. This means your Database actually wraps PDO and is what all other classes work with for db operations. The Main or Base class may not even be needed unless you are trying to implement active record or something.
class Database {
static protected $instance;
/**
* #var PDO
*/
protected $connection;
protected function __construct($dsn, $user, $pass, $attrs = array()) {
// create pdo instance and assign to $this->pdo
}
public static function getInstance() {
if(!self::$instance) {
// get the arguments to the constructor from configuration somewhere
self::$instance = new self($dsn, $user, $pass);
}
return self::$instance;
}
// proxy calls to non-existant methods on this class to PDO instance
public function __call($method, $args) {
$callable = array($this->pdo, $method);
if(is_callable($callable)) {
return call_user_func_array($callable, $args);
}
}
}
class Main {
protected $db;
public function __construct() {
$this->db = Database::getInstance();
}
}
class User extends Main{
public function __construct() {
parent::__construct();
}
public function findById($id) {
$qry = $this->db->prepare('SELECT * FROM users WHERE userID = :userID');
$qry->execute(array(':userID' => $id));
$results = $qry->fetchAll(PDO::FETCH_ASSOC);
return $results
}
}
Related
I have what seems like a simple query but I have not found an answer elsewhere.
I have 2 classes, one called DB which essentially connects to the database and can then run queries. I instantiate it at the top of the document $db= new DB; and I can then run a series of queries on the database throughout the page.
The issue I am having is that I want to use this instance within another class I have called User.
I know I can either instantiate again but this does not make sense OR pass the instance of DB when instantiating User, for instance $user = new User($db); but considering the $db instance will be used by most classes I am going to create I am thinking there is a better solution to import it into other classes.
I have looked at the global route but I read it is bad practice + I am getting unexpected global error
class User{
global $db;
public function __construct()
{
var_dump($this-> db);
}//end constructor
}//end class
Since your DB client will be instantiated once and then used everywhere else my initial thought was to recommend passing it as a constructor parameter (dependency injection), but since you are not fan of this approach, I would recommend making your DB client a singleton class, which means it can only be instantiated once and any subsequent attempt would return the same instance everywhere.
You can see a detailed response about singleton classes in PHP at Creating the Singleton design pattern in PHP5.
As a quick example, your DB would look like similar to this:
final class DB
{
public static function getInstance()
{
static $inst = null;
if ($inst === null) {
$inst = new self();
}
return $inst;
}
private function __construct()
{
// your code here ...
}
// your code here ...
}
And then, on your User class you would just get the DB class instance:
class User {
// your code here ...
public function doSomething() {
$db = DB::getInstance();
// your code here ...
}
}
PHP does not handle scopes like Javascript does, your $db is undefined.
The scope of a variable is the context within which it is defined. For the most part all PHP variables only have a single scope. This single scope spans included and required files as well […] Within user-defined functions a local function scope is introduced. Any variable used inside a function is by default limited to the local function scope.
Source: http://php.net/manual/en/language.variables.scope.php
This means that there is only a global scope and a function/method scope in PHP. So, either pass the $db instance into the method as a collaborator
class User{
public function __construct() {}
public function getInfo(Database $db) {
$db->query( /* ... */ );
}
}
$user = new User();
$db = new Database();
$user->getInfo($db);
or pass it in the constructor (dependency injection)
class User{
private $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function getInfo() {
$this->db->query( /* ... */);
}
}
$db = new Database();
$user = new User($db);
$user->getInfo();
I'm trying to learn how to properly code PHP OOP.
This is where I'm running into issues.
I created several classes that extend main Application class and I want to make things work properly.
I have main file that's index.php that looks like this:
include_once('classes/Application.php');
include_once('classes/Configuration.php');
include_once('classes/Database.php');
$app = new Application;
$config = new Configuration;
$db = new Database;
var_dump($app->db_connected);
var_dump($db->db_connected);
$db->connect($config->dbhost, $config->dbuser, $config->dbpass, $config->dbname);
var_dump($app->db_connected);
var_dump($db->db_connected);
The output is:
1. bool(false)
2. bool(false)
3. bool(false)
4. bool(true)
My main application file looks like this:
class Application {
public $db_connected = false;
}
And my Database class looks like this:
class Database extends Application {
function connect($dbhost, $dbuser, $dbpass, $dbname) {
if(!$this->db_connected) {
mysql_connect($dbhost, $dbuser, $dbpass) or die(mysql_error());
mysql_select_db($dbname) or die(mysql_error());
$this->db_connected = true;
}
}
}
So the question is, why would line #3 of the output of index.php display false? The db_connected property has been overridden in Database class and set to TRUE, but it still returns false.
Although when accessed directly from Database class instance it shows TRUE correctly. What's the deal here?
Also when does the class EXTEND command occurs? Whenever parent class' instance is created or I have to manually create instance of the child class?
It seems you are reaching for the concept of of a static variable all instances of a class share the same static variable so using the new twice will not be an issue.
You can see the code on ideaone.
// your code goes here
class Application {
static $db_connected = false;
}
class Database extends Application {
function connect() {
if(!static::$db_connected) {
static::$db_connected = true;
}
}
}
$app = new Application;
$db = new Database;
var_dump(Application::$db_connected);
var_dump(Database::$db_connected);
$db->connect();
var_dump(Application::$db_connected);
var_dump(Database::$db_connected);
Your comment make me think you are looking for a better pattern all together. I would like to throw out some key principles namely OCP and LSP SOLID.
In this case you would avoid having Application being an instance of Database but instead use dependency injection. Here is the refactored code.
class Database {
private $db_connect = false;
public function connect () {
if(!$this->db_connect) { /* do connection */ }
}
}
class Application {
private $db;
public function setDatabse(Database $db) {
$this->db = $db;
}
public function getDatabase() {
return $this->db;
}
}
$db = new Database;
$app = new Application;
$app->setDatabase($db);
$app->getDatabase()->connect();
This line is your hint
Although when accessed directly from Database class instance it shows TRUE correctly. What's the deal here?
You have 2 instances. Above you are checking $db instance which you connected with, and then you print from $app which was never connected. They are separate entities, one is connected one is not.
Extend occurs as soon as the file is loaded, read by the php interpreter, this happens regardless of ever using the class.
Extend is called from the child and inherits everything form the class it extends. So if you call a child method in the parent, well you are doing it backwards. It goes one way, Prent -> Child.
I would use Dependance injection for the database, then you can reuse it's code.
Like this:
//parent class
class Application {
//holds a reference to the Database class
protected static $db_conn = false;
public function __construct($db){
self::$db_conn = $db;
}
}
//child class of Application
class Application2 extends Application {
public function getSomething($id){
return self::$db_conn->getbyId($id) ;
}
}
//separate utility class
class Database{
static $conn;
public function __construct( $dbhost, $dbname, $dbuser, $dbpass, $dbname) {
static::$conn = mysqli_connect($dbhost, $dbuser,$dbpass,$dbname);
}
public function getbyId( $id ){
..code to get stuff by id using $conn - previous connection ...
return $result;
}
}
$db = new Database("myhost", "myuser", "mypassw", "mybd");
$app = new Application2( $db );
$app->getSomething(1);
//create another app with the same database connection, this is the value of injecting it.
$second_app = new Application2( $db );
See you can reuse database over and over, you can replace it without changing the code in Application as long as the calls for the functions of the Database class don't change. Each thing is responsible for it's own business.
This is called separation of concerns.
Inheritance is good, when it's needed. You might have an basic application for free users of you're services and then extend that with a premium application for paid members. Sense they paid they get all the free functionality, but also the premium stuff to.
In my example above the database is something they both need, as well as other things will probably use this. Such as a login system may need a database connection, payment system might, a shopping cart might. These are all separate objects, they don't / nor should they extend off of one Master Class, that's a bad idea. Keep them separate.
STATIC
I seen mention of the :: static object operator. My example is a bit flawed when using the static property protected static $db_conn = false;
$app = new Application2( $db );
$second_app = new Application2( $db ); //assigning db 2x is not needed.
The reason for :: and the -> normal way. Is that static :: is shared across all instance of a class, and -> is just this instance of the class. I had assigned the $db class to a static variable 2 times a better way would have been like this.
//parent class
class Application {
protected static $db_conn = false;
//separate method then construct.
public function connect($db){
self::$db_conn = $db;
}
}
//we'll keep the rest of the code the same here.
$db = new Database();
$app = new Application2();
$app->connect( $db );
$second_app = new Application2();
$second_app->getSomething(1);
Now in this example $second_app never ran it's connect method. But because the first $app did and because the static for the database variable protected static $db_conn. Now all classes that have extended the Application class have a database connection. This is what static does. It's value is shared across all instance of the class. So when you see :: think all class instance and when you see -> think only this class instance. It's actually one thing I love about php, makes it so much easier to keep track of then in some other languages.
Not to confuse you but the other use of the :: is not actually needing an instance at all. Assume you have a Config class like this.
class Config{
static $db = 'hello';
static $items = array('one' => 'item 1' );
private __construct(){} // no construction allowed
static function getItem( $which ){
return self::$items[$which];
}
}
Now without ever creating an instance of the class by calling new Config() , you can simply.
echo Config::$db;
// prints hello
echo Config::getItem('one');
// prints 'item 1'
This is quite use full for config type classes. Where they are an empty shell just used to store data in and you don't need an object for them, essentially a way to keep things organized. So tying this in to the previous examples
$db = new Database(Config::$myhost, Config::$myuser, Config::$mypassw, Config::$mybd);
In your case best OOP practice is to use Mediator pattern. Concrete Mediator will be Application class:
class ApplicationBase {
private $db;
private $cfg;
public function setDb(Database $db) {
$this->db = $db; return $this;
}
public function setConfig(Config $cfg) {
$this->cfg = $cfg; return $this;
}
}
class Application extends ApplicationBase {
public function getDsn() {
return $this->cfg->getDsn();
}
public function getDbUser() {
return $this->cfg->getDbUser();
}
public function getDbPass() {
return $this->cfg->getDbPass();
}
public function getConnection() {
return $this->db->getConnection();
}
}
class AppComponent {
protected $app;
public function __construct(Application $app) {
$this->app = $app;
}
}
class Config extends AppComponent {
private $dsn;
private $dbuser;
private $dbpass;
// ... getters and setters
}
class Database extends AppComponent {
private $connection;
private function connect() {
$this->connection = new PDO(
$this->app->getDsn(),
$this->app->getUser(),
$this->app->getPass()
);
}
public function getConnection() {
if (null === $this->connection) $this->connect();
return $this->connection;
}
}
class Model extends AppComponent {
protected $table;
// Model stuff here
}
class Content extends Model {
public function getNews() {
$db = $this->app->getConnection();
return $db->query("SELECT * FROM $this->table LIMIT 5")->fetchAll();
}
}
Such architecture will be enough for simple, clean-looking applications and classes will be ready for easy unit-testing:
$app = new Application();
$cfg = new Config($app);
$db = new Database($app);
$app->setDb($db)->setConfig($cfg);
$content = new Content($app);
$news = $content->getNews();
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.
I know there were some questions about this opened, but I need a more "specific" example and solution.
Here is my Example:
databse.class.php
class db{
public function connect($conStr){...}
}
func.class.php
func class{
public insert_song(){
//ineed to use the conenct method from database
//then I would INERT INTO...
}
}
Questions:
1) Should I require or extend the db class in func class?
2) If I require, will the scope of the db class functions will remain? (lets say if I have a private variable there, will it be accessible from the out side?)
No, you should not require or extend the database class.
No, private variables or methods never get available outside the class. Protected variables are available to child classes only, public variables are...public.
You could require the file in which the database class lives somewhere in your config, so you can instantiate the database class wherever and whenever you want. But, as you'll probably need only one instance of the database object, you could just instantiate it in the config and pass it around using Dependency injection.
This basically means that you pass the database object to other objects needing one. A common way of dealing with database objects is using Constructor injection, although setter injection would do as well.
What you do is something similar to this:
// config:
$db = new Database;
$db->setConnectionValues();
$fooClass = new Foo($db);
$fooClass->insertSomething();
// fooClass:
class Foo
{
private $db;
public function __construct(Database $db)
{
$this->db = $db;
}
public function insertSomething()
{
$this->db->query("INSERT");
}
}
This solves most of your dependency problems.
// changed the class name, func is not good for a class name.
class Foo {
protected $db;
public setDb($db) {
$this->db = $db;
}
public insert_song(){
//ineed to use the conenct method from database
//then I would INERT INTO...
$this->db->insert(...);
}
}
Example:
// omited the error handling.
$db = new db();
$db->connect();
$foo = new Foo();
$foo->setDb($db);
$foo->insert_songs();
As part of Abstraction, you should separate the responsibilities for your classes. Your Database class should care about your Songs (which is how you should name it) class.
If your Songs class uses the Database class, you should inject it in the constructor as follows:
<?php
class Database {
public function connect($conStr) {
/*
* Connect to database here
*/
}
}
class Songs {
private $db;
public function __construct(Database $db) {
$this->db = $db;
}
public function insert_song($song) {
/*
* Now you can use $this->db as your database object!
*/
}
}
I've been a procedural programmer for over 4 yrs and it's time to start looking into OOP. With that said, let's say I needed to call two methods in my class. Each method requires a connection to the DB so that's two trips to the DB, which also opens multiple connections.
Can this be avoided by having some sort of code in the application layer (constructor?) or does a connection pool have to be setup on the DB side? And just for kicks, I'm not using mysql; I'm using mongodb with codeigniter.
Here's what I have so far, not sure if it's ideal to use?
Here's where I setup my DB info:
database_conn.php
class Database_Conn extends Model {
function _connect() {
$m = new Mongo("localhost:27017", array("persist"=>"x"));
$db = $m->selectDB( "foo" );
return $db;
}
}
sample model file
class Home_model extends Model {
public function __construct() {
// Establish connection to "profiles" table
$this->db_conn = Database_Conn::_connect()->selectCollection( "profiles" );
}
function getMyProfile($username) {
$data = $this->db_conn->findOne(array("username" => $username) );
return $data;
}
function getAll() {
$data = $this->db_conn->find();
return $data;
}
}
you should use singleton pattern
EDIT:
the way you did it, it is possible to call _connect multiple times, which means reconnecting.
singleton implementation usually means you have to make constructor private/protected and define a getInstance method which creates connection on first call and returns the created connection on later calls.
this is what i would do:
class Database_Conn extends Model {
static protected $_instance;
protected $db = null;
final protected function __construct() {
$m = new Mongo("localhost:27017", array("persist"=>"x"));
$this->db = $m->selectDB( "foo" );
}
static public function getInstance() {
if (!(self::$_instance instanceof self)) {
self::$_instance = new self();
}
return self::$_instance;
}
public function getConnection() {
return $this->db;
}
final protected function __clone() { }
}
and then use Database_Conn::getInstance()->getConnection() to get the connection object.
You should look into a manager class for your db connections. Then you can have one central place where you request connections from. If there is already an open connection the manager can return that instead of returning a new connection.
This would be one approach. There are tons of examples out there about how to implement something like this. There already some for mysql and mssql. But you could surely extend for your db.
Use a database layer. Dibi is a great library in this case. http://dibiphp.com