Hey sorry for the stupid question. I have read lots about oop in php so i decided to try. i have a blog running procedural php and all works fine but i have mysql not mysqli on the code and i decided to upgrade to the new mysqli. the problem here is really query the database to get results. i have been on the problem for two days now. here's a code example of what i want to implement.
class myDB extends mysqli
{
//perform mysqli connection to host here and return $connection_handle
}
class siteConfig
{
private function getConfig($id)
{
$res = $connection_handle->query("SELECT * from config where id='1'");
$row = $res->fetch_assoc();
return $row['option'];
}
}
on the main index file i would do this
$c = new siteConfig();
echo $c->getConfig(1);
//and this will return the result of the query.
also please pardon my programming logic and still a very terrible newbie to the oop world
any ideas will be helpful thank you.
PS
this is working example of the code am using
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
i have defined the constants already and the connection is successful but the select is not working. on the index page this goes [code] include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
please let me know where am missing it or if possible refactor the code for me where neccessary
Why not just extend the mysqli class and add your functions to myDB?
class myDB extends mysqli
{
public function getConfig($id) // thanks cbuckley
{
$res = $this->query("SELECT * from config where id='1'");
$row = $res->fetch_assoc();
return $row['option'];
}
}
$db = new myDB;
$db->getConfig($id);
You can call any mysqli function inside myDb by using the $this keyword (which refers to itself and since "it self" extends mysqli, it will have all the functions mysqli has + the ones you add)
It's good to keep the separation between your database connection and any business logic, so your example is good. There are just a couple of extra things that need sorting out, namely how the application logic has access to the database handler. Here's an example:
class MyDB extends mysqli {
// any custom DB stuff here
}
class SiteConfig {
protected $db;
public function __construct(MyDB $db) {
$this->db = $db;
}
public function getConfig($id) {
$statement = $this->db->prepare('SELECT * FROM config WHERE id = ?');
$statement->bind_param('i', $id);
if ($statement->execute()) {
$row = $statement->get_result()->fetch_assoc();
return $row['option'];
}
}
}
$db = new MyDB('host', 'user', 'password', 'db');
$config = new SiteConfig($db);
var_dump($config->getConfig(1));
A couple of points of interest here:
Dependency injection: passing $db into your config class
Separation of concerns: the SiteConfig class is not responsible for setting up the database connection, thus keeping its role clean and well-defined
Method and property visibility: $config->db is
declared protected, so it can't be accessed outside of the scope of the class
Type hinting: forcing the first parameter of SiteConfig's constructor to be an instance of MyDB
Class properties: setting the $db instance as a property of the SiteConfig class, so it can be used in getConfig()
Method and property visibility: $config->db is
declared protected, so it can't be accessed outside of the scope of the class
Prepared statements: more efficient queries that get protection against SQL injection for free
Related
Today i tried to convert my functions to PHP Class.
I tried with some basic steps.
<?php
class DataBase {
private $host;
private $user;
private $password;
private $db;
private $mysqli;
function __construct() {
$this->host = "localhost";
$this->user = "root";
$this->password = "";
$this->db = "my_database";
$this->mysqli = new mysqli($this->host, $this->user, $this->password, $this->db);
}
function __destruct() {
$this->mysqli->close();
}
public function query($query, $params = '', $bind_result) {
$stmt = $this->mysqli->prepare($query);
//Need to change this to process the array of params
$stmt->bind_param('i', $params);
$stmt->execute();
//Change this to handle array of bind
$stmt->bind_result($bind_result);
//Loop the result and store it in a temp array
$stmt->fetch();
//Don't print the statement. Just close the statement and return the array.
printf("%s\n", $bind_result);
/* close statement */
$stmt->close();
}
}
?>
I have to now create another class. I created one dummy table in database.
<?php
class Dummy {
private $database;
function __construct() {
$this->database = new Database();
}
public function getAllDummy() {
$query = "SELECT name FROM dummy WHERE id = ?";
$this->database->query($query, 1, 'name');
}
}
?>
But I don't think it is the right way to do the things. I feel some of them are in the right way and some of them are wrong.
When i call the query() function, Do i need to connect the database all the time in every classes' construct method? Or Do i need to change the Database class to static functions? So i can call the functions like Database::query();
It seems i need to create everything from the start. Is such a model already available in internet? like cakephp, codeigniter
I would like to recommend you to read something about ORM for PHP. For example I m using Doctrine 2 (http://www.doctrine-project.org/) It is kinda complex but definitely worth to learn. There is everything you are trying to code already done, so why you should make it again?
In your OOP principe there are some mistakes.
You are creating Database instance for every class like Dummy, if you will have class Users, Articles, you will create 3x Database, it isnt really good. You should make Database as service or Singleton and make it just once. Good solution for this can be Dependency injection (http://en.wikipedia.org/wiki/Dependency_injection).
Also I would recommend you to generalize whole Dummy class, to make it more general. Dont make method "getAllDummy" but for example "getAll($tableName)"so you can use it for every table.
Besides Doctrine (Which is powerfull and almighty already but still to complex) I can suggest you db.php (http://dbphp.net) which does everything what doctrine but is single file and is very easy to use. Cons: It is not well documented yet and has no big community yet.
Sorry for the stupid question am a newbie to oop in php...i have a proble wiriting a mysqli class thet returns a connection handler that enable me the connection handler in other classes/methods. i run a small procedural blog n wanted to convert to oop.
heres a my working code example. please refactor for me where necessary. Thank in advance.
$db_link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
class myDB extends mysqli
{
public function getConfig($id, $db_link) // thanks cbuckley
{
$db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
i have defined the constants already and the connection is successful but the select is not working. on the index page this goes
include('inc/dbc.php');
$db = new MyDB();
echo $db->getConfig(1, $db_link);
any help is appreciated
Your question is not very specific, and I have the feeling you're not really aware what your concrete problems are. You've already accept an answer that gives you some code but puts you in the wrong direction as it does not solve your underlying problem and wastes code.
The first thing you should know if you want to make use and benefit of the object oriented interface of PHP's mysqli extension is, that the Mysqli class represents the database connection (the "link" as it was named for a procedural approach) already:
require('inc/dbc.php');
$dbConnection = new Mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
That's already it. Sure you might want to use some error handling here:
if ($dbConnection->connect_error)
{
throw new Exception(
sprintf('(#%d) %s', $dbConnection->connect_errorno,
$dbConnection->connect_error)
);
}
Throwing exception instead of let's say die('message') is done, because you can easily create an exception handler so that you can display a more useful response to the user from within a central place instead of handling each exceptional error-case where it appears (actually at the place where die would be).
You can also log and mail the backtrace so you can fix things more easily. Naturally you do not need to use exceptions, however the rule of thumb is to use die only in scripts you throw away in let's say a week and it does not work well with object oriented design.
As you will need this code anyway in all places where you will need your database connection, you can create your own connection object to bring those parts together as they belong together:
class DatabaseException extends Exception
{
}
class DatabaseConnection extends Mysqli
{
public function __construct($host, $user, $password, $database = "", $port = NULL, $socket = NULL) {
parent::__construct($host, $user, $password, $database, $port, $socket);
$this->throwConnectionExceptionOnConnectionError();
}
private function throwConnectionExceptionOnConnectionError() {
if (!$this->connect_error) return;
$message = sprintf('(%s) %s', $this->connect_errno, $this->connect_error);
throw new DatabaseException($message);
}
}
The usage is actually pretty straight forward and very much the same, only the name of the class varies and it's definition needs to be loaded:
require('inc/dbc.php');
require('inc/database.php');
$dbConnection = new DatabaseConnection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
As written, the connection object already represents your database connection. So every part in your application that needs it, has to ask for it. Let's review your example function:
function getOption($id, $db_link)
{
// $db_link = $this->db_link;
$res = mysqli_query($this->db_link,"SELECT * from config where id='1'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
I renamed the function and I commented the first line, even this might be what you want. Actually, if that function would be part of the DatabaseConnection object, it could work like this:
class DatabaseConnection extends Mysqli
{
...
public function getOption($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
As this example demonstrates, the database connection is already there. However, this is not advisable. Imagine you not only have options but this and that and such and what not more. You would create one function after the other all in one class. Well for a little application that might even so work right, but imagine more and more. You would get one very large class that is responsible for many things. So it would be bad to do this, even if you can use $this already to prepare the statement.
Also take note that you should prepare statements. This has been answered here numerous times, if you're not used to it, read about it, it's worth the lines. There are better ways to not repeat code (DRY: Don't repeat yourself) while stepping into object oriented (you should even already do this with procedural).
So as to have this all in one class would be a problem, you instead put it in a class of it's own:
class DatabaseModelBase
{
protected $connection;
public function __construct(Connection $connection) {
$this->connection = $connection;
}
protected function prepare($query) {
$connection = $this->connection;
$statement = $connection->prepare($query);
if (!$statement) {
throw new DatabaseException(
sprintf('(%s) %s', $connection->error, $connection->errno)
);
}
return $statement;
}
}
class Option extends DatabaseModelBase
{
public function find($id) {
$statement = $this->prepare('SELECT `option` FROM config WHERE id=?');
$statement->bind_param('i', $id);
$statement->execute();
$statement->bind_result($option);
$statement->fetch();
$statement->close();
return $option;
}
}
This has some extended error handling again, because most often mistakes are made in the SQL query. And as you can see the individual function to fetch some specific data is placed in it's own class. You can use such classes to group the fetching and updating for specific datatypes.
Usage in full:
$dbConnection = new Connection(DB_HOST, DB_USER, DB_PASS, DB_NAME);
$option = new Option($dbConnection);
$optionValue = $option->find(1);
echo $optionValue; # value for option with ID1
The names of the Option object probably is not well, I tried to keep the example lightweight but also offer some separation. For other scenarious you might want to prefer some different kind how to access the db connection, because it is injected into Option via it's constructor, Option does not deal any longer with the details how the database connection is being created.
For example you can make the database connection object more smart only to connect to the database the first time prepare or query is actually used with it. So that requests to your website that do not need a database connection would not needlessly connect to the database.
You find more examples in other questions and you might want to learn about dependency injection. Also you always want to keep things apart from each other, so you have some objects that are only lightly connected to each other.
How to successfully rewrite old mysql-php code with deprecated mysql_* functions?
Dependency Injection simple implementation
I would suggest moving the connect to the database also inside the class:
class myDB extends mysqli
{
private $link;
public function Connect()
{
$this->link = mysqli_connect(DB,HOST,DB_USER,DB,PASS,DB_NAME) or die(mysql_error());
}
public function getConfig($id) // thanks cbuckley
{
$res = mysqli_query($this->link,"SELECT * from config where id='$id'");
$row = mysqli_fetch_array($res);
return $row['option'];
}
}
And use it like this:
include('inc/dbc.php');
$db = new MyDB();
$db->Connect();
echo $db->getConfig(1);
I recommend you to Wrap the mysqli class in a new Class instead extending it:
For those Classes, where you need the Configuration, just include the Configuration with Dependency Injection. This brings you the Benefit, that the Code, where you need the Configuration, don't need to know about the Way, Configuration get its values.
If you later decide to parse Configuration from a iniFile, you only need to change the Configuration-Class or even better, write a new Class which implements ConfigurationInterface and inject the new ConfigurationClass.
class Configuration implements ConfigurationInterface{
private $mysqli;
public function construct(mysqli $mysqli) {
$this->mysqli = $mysqli;
}
public function get($key)
{
// You should escape this query to prevent SQL-injection
$res = $this->mysqli->query("SELECT * from config where id='$key'");
$row = $res>fetch_array();
return $row['option'];
}
}
interface ConfigurationInterface {
public get($key);
}
Use it like this:
$mysqli = new mysqli('localhost', 'root', 'pw', 'my_db');
$config = new Configuration($mysqli);
var_dump($config->get(0));
I'm kinda new to PDO with MYSQL, here are my two files:
I have a connection class that I use to connect to the database:
class connection{
private $host = 'localhost';
private $dbname = 'devac';
private $username = 'root';
private $password ='';
public $con = '';
function __construct(){
$this->connect();
}
function connect(){
try{
$this->con = new PDO("mysql:host=$this->host;dbname=$this->dbname",$this->username, $this->password);
$this->con->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
}catch(PDOException $e){
echo 'We\'re sorry but there was an error while trying to connect to the database';
file_put_contents('connection.errors.txt', $e->getMessage().PHP_EOL,FILE_APPEND);
}
}
}
I have an account_info class that i use to query the data from the database:
class account_info{
function getAccountInfo(){
$acc_info = $this->con->prepare("SELECT * FROM account_info");
$acc_info->execute();
$results = $acc_info->fetchAll(PDO::FETCH_OBJ);
foreach ($results as $key) {
$results->owner_firstname;
}
}
}
I include both these files in my index.php page:
include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';
$con = new connection();
$info = new account_info();
$info->getAccountInfo();
I just cant get it to work I'm not getting any output, I think it has something to do with the scope, but I don't know the correct why to fix it as I'm new to this PDO and OOP stuff.
Thanks in advance.
Solution 1
Replace class account_info { with class account_info extends connection {
Replace
$con = new connection();
$info = new account_info();
with
$info = new account_info();
and it should work.
Solution 2 (suggested)
I highly suggest you to solve your problem with dependency injection in this case.
Just replace your account class with:
class account_info {
private $con;
public function __construct(connection $con) {
$this->con = $con->con;
}
public function getAccountInfo(){
$acc_info = $this->con->prepare("SELECT * FROM account_info");
$acc_info->execute();
$results = $acc_info->fetchAll(PDO::FETCH_OBJ);
foreach ($results as $key) {
$results->owner_firstname;
}
}
}
and use it in index.php like this:
include_once 'classes/connection.class.php';
include_once 'classes/accountinfo.class.php';
$con = new connection();
$info = new account_info($con);
$info->getAccountInfo();
Explanation
As a general good rule: always specify the scope keyword for functions (public, protected or private).
The first solution is called inheritance and what we basically did was extending the account class with the connection class in order to inherit all the methods and properties from the connection class and easily use them. In this case you have to watch out for naming conflicts. I suggest you to take a look at the class inheritance in the PHP manual.
The second solution is called dependency injection and it is a wildly encouraged design pattern that makes your classes accept other classes in their constructor in order to explicitly define the class dependency tree (in this case account depend from connection and without the connection we can't make account work).
Another, of thousands of possible solution, would be the one that someone posted below which is a design pattern called Singleton. However that patter has been reevaluated recently as anti-pattern and should not be used.
A common method is to use a singleton pattern in your database class.
Something like this:
class connection {
private static $hInstance;
public static function getInstance() {
if (!(self::$hInstance instanceof self)) {
self::$hInstance = new self();
}
return self::$hInstance;
}
/* your code */
}
Then, you can simply use
$database = connection::getInstance();
$database->con->prepare(....)
etc
I started using PHP classes and looked into OOP.
I played around by creating a Database class that looks something like this (snippet):
class Database
{
private $link;
private $result;
private $count;
function connect()
{
$this->link = mysql_connect(DB_HOST, DB_USER, DB_PW);
$return = $this->link ? 'Connected to database.' : 'Failed to connect.';
$this->open(); // I have another function in this class to select the db
echo $return;
}
function query($query)
{
$this->result = mysql_query($query);
}
function fetch()
{
return mysql_fetch_assoc($this->result);
}
function count()
{
$this->count = mysql_num_rows($this->result);
return $this->count;
}
}
Just to test, I created another class called Guestbook that looks like this:
class Guestbook
{
function fetch()
{
Database::query('SELECT * FROM guestbook LIMIT 2');
while($row = Database::fetch()){
$result_array[] = $row;
return $result_array;
}
}
Now I tested calling the functions:
$db = new Database();
$db->connect();
$db->query('SELECT * FROM test');
while($row = $db->fetch()) {
echo $row['id'].'<br />';
}
echo $db->count();
$db->close();
This works as expected. So I went on with the Guestbook class:
$db->connect();
$guestbook = new Guestbook();
$results = $guestbook->fetch();
foreach($results as $gb) {
echo $gb['id'];
}
echo $db->count(); // HERE'S MY PROBLEM !
$db->close();
Everything works as I wanted, but the second time I call $db->count() it echos the previous count and not 2 (as I set LIMIT 2 in the Guestbook fetch function).
How do I interact with these classes properly, so I can use something like $db->count() globally?
Thanks in advance for any hints or solutions!
First off, there is no reason to wrap mysql_* implementations in OOP. IF you are going to do OOP then just use Mysqli or PDO which have OOP classes you can extend.
Secondly you want to hold an instance of the Database in the GuestBook class, not make it an extension of the Database class itself.
It is hard to give you a definitive advice on how you could wrap your database accessor with OOP and still access the count() globally.
Clearly your code is wrong.
by using the notation
Database::query
you are referring to some kind of static methods on the Database class which does not seem to be the intent here. It looks like your code does not crash because of some backward compatibility with PHP4.
you could rewrite Guestbook along this way :
class Guestbook
{
private $db;
function __construct(&$db) {
$this->db = $db;
}
function fetch($option)
{
$this->db->query('SELECT * FROM guestbook LIMIT 2');
while($row = $this->db->fetch()){
$result_array[] = $row;
return $result_array;
}
}
and then
$db = new Database();
$db->connect();
$guestbook = new Guestbook($db);
$results = $guestbook->fetch();
echo $db->count();
This technique uses a pattern known as "Dependency Injection"
Why would you use count from the db class when you have the results from the guestbook->fetch() method?
This does exactly the same trick:
echo count( $resutls );
see the $db is a object of the class Database
never access the function OR property of the Guestbook
you can get this directly with count( $resutls )
OR may have to go with the inheritance concept
Thanks
You mixing static with instantiated versions of your class. If you want to be able to create multiple instances of a class, you should have a __construct function. While it's not required, it's best practice to have one.
You are creating a new instance and assigning it to the $db variable ($db = new Database();). But then in your GuestBook class you are referencing the database class statically (Database::). That syntax references the "base" class which is the same across all instances. What you want to do is reference the instance of the database class you created. Typically you would pass the database instance to use into the GuestBook class in the constructor, store that in a class variable, then reference it using $this.
class Guestbook
private $db = null;
{
function __construct($db) {
$this->db = $db;
}
function fetch($option) {
$this->db->query('SELECT ...');
...
}
}
$db = new Database();
$guestbook = new Guestbook($db);
I am trying to convert code from mysql to mysqli.
The code uses a single mysql_connect in a file which is included by every other file.
mysql_connect returns a MySQL link identifier that is a superglobal so you can rely on having a database connection available in any of your own functions.
It looks like with mysqli_connect this is not the case, the object returned isn't global.
Does this mean I have to add : global $mysqli; at the top of every function, or is there an way of making it a superglobal?
Relying on the fact that PHP will use the last opened connection resource if you don't specify one, is probably not a very good idea.
What happens if your application changes and you need two connections, or the connection is not there?
So it seems you need to do some refactoring anyway.
Here's a solution similar to Karsten's that always returns the same mysqli object.
class DB {
private static $mysqli;
private function __construct(){} //no instantiation
static function cxn() {
if( !self::$mysqli ) {
self::$mysqli = new mysqli(...);
}
return self::$mysqli;
}
}
//use
DB::cxn()->prepare(....
I usually make a function:
$mysqli = new mysqli(...);
function prepare($query) {
global $mysqli;
$stmt = $msqyli->prepare($query);
if ($mysqli->error()) {
// do something
}
return $stmt;
}
function doStuff() {
$stmt = prepare("SELECT id, name, description FROM blah");
// and so on
}
and then call that. That being said, I've since abandoned mysqli as being too bug-ridden to be considered usable. Shame really.
A very simple way to do this would be with a fixed database class, just to hold the mysqli connection object:
class Database {
public static $connection;
}
Database::$connection = new mysqli(HOST, USERNAME, PASSWORD, DATABASE);
Then you can access it in the normal ways:
$sql = 'SELECT * FROM table';
$result = Database::$connection->query($sql);
$result = mysqli_query(Database::$connection, $sql);
echo 'Server info ' . mysqli_get_server_info(Database::$connection);
To introduce some oop to you and solve your problem, you could use a class like this:
class MyDatabase
{
private static $_connection;
public static function connect()
{
$mysqli = new mysqli(...);
self::$_connection = $mysqli;
}
public static function getConnection()
{
return self::$_connection;
}
}
In your database-connection file you would load this class and execute MyDatabase::connect(); once.
To get the $mysqli-connection anywhere in your script, just call MyDatabase::getConnection();.