I am trying to create a class with various methods that will need to interact with a database, so I am trying to create a database object using mySQLi in the __construct, depending on if I still have a db connection or not, but I am unsure of how I can access the db object from within a method as I am new to object oriented PHP, here is my code,
class my_class
{
private $db_host = '';
private $db_user = '';
private $db_pass = '';
private $db_name = '';
function __construct() {
$myconn = new mysqli($this->db_host,$this->db_user,$this->db_pass,$this->db_name);
if($myconn) {
$this->con = true;
return true;
} else {
return false;
}
}
private function my_function(){
//not sure how I can access the database object from here to run a query
}
}
any advice on how I can improve this, or approach this in a better way, will be appreciated!
Please excuse my ignorance on the subject!
Thanx in advance guys!
Store the object ($myconn) in an member of the object.
$this->oConnection = $myconn;
Then you can simply use $this->oConnection to access your object.
Mind the deceleration in of your new member private $oConnection at the top of your class.
Related
I am wondering if I use mysql with php secure. This is my class:
class DB{
public $mysqli = null;
public $result = array();
private $_host = 'localhost';
private $_user = 'root';
private $_password = 'root';
private $_db_name = 'DBNAME';
public function __construct()
{
$this->mysqli = new mysqli($this->_host,$this->_user, $this->_password, $this->_db_name);
if ($this->mysqli->connect_errno){
echo "Error MySQLi: (" . $this->mysqli->connect_errno . ") " . $this->mysqli->connect_error;
exit();
}
$this->mysqli->set_charset("utf8");
}
public function __destruct(){
$this->mysqli->close();
}
public function query($query){
$this->result = $this->mysqli->query($query);
if($this->result){
return $this->result;
}else{
return false;
}
}
Is that way to comunicate with database good enough or should I use Doctrine ?
I am asking because something strange is in my code. If I vardump any object contains reference to DB object, I can see :
["_host":"DB":private]=> string(9) "localhost" ["_user":"DB":private]=> string(4) "root"
["_password":"DB":private]=> string(4) "root" ["_db_name":"DB":private]=> string(10) >"DBNAME" }
If you are worried about the DB settings shown on var_dump, I suggest you place those settings in a config file and send those configs as params.
Personally, I wouldn't worry about it. If someone has access to your object (maybe another shared object) they probably have the ability to read your settings. The only positive I see with having a config file is that you can update those configs without having to touch the php codebase.
Is there a reason why you think this would be an issue?
Also your code structure is nice, keep it extracted from mysqli, don't switch to an extend. This will give you flexibility in the future should you decide to switch to PDO or any other better extensions that come up.
Why reinvent the wheel? Your query function pretty much does what mysqli_query is already doing for you. I would just use the base mysqli class as you're already doing by making this class extend that one
class DB extends mysqli {
private $_host = 'localhost';
private $_user = 'root';
private $_password = 'root';
private $_db_name = 'DBNAME';
public function __construct()
{
parent::__construct($this->_host,$this->_user, $this->_password, $this->_db_name);
}
}
Your question is like "should I put a hat or a cap ?".
Actually, there is no best way to deal with a database. It depends of witch approach you have.
If you prefer write SQL code, then your solution is good and works well for your usage.
However, if you do not want to write SQL query and work only with objects, then you will prefer use doctrine.
I've been taking help from this site by years now, but I have never asked, so this is my first question here. This is a theoretic question, I would like to know if I'm thinking in the right way.
First of all, sorry for my English.
I was thinking if I could simplify my existing MySQL object.
For the connection, I use the singleton pattern to ensure that my app connect only one time during script execution. So, in every class, when I want to use MySQL, a get the instance.
$db = db::getInstance();
$result = $db->query("SELECT * FROM data;");
the $result is a dbResult class, on which I can use loops (while($row = $result->nextRow()) {...}), jump to row number, etc...
after all things are done, then I $result->free(); the result class.
Question 1.
Why not return an associative array instead of the dbResult class? I could use a foreach on it. But what about a result with 1.000.000 rows?
Question 2.
Do I have to get the instance every time I want to use SQL?
class db{
...
private static $instance;
...
public static function query($_query){
if (!self::$instance){
self::$instance = new db(); //first we need to connect...
self::query($_query);
}
else{
//execute query, then load result in array,
//or in case of insert, return insert_id
return $return_array;
}
}
In this case, I can simply call a query from anywhere in my code without instantiating the db object.
$result = db::query("SELECT * FROM data;");
...
//or insert
db::query("INSERT INTO test VALUES ('test_value');");
Would be this a bad practice?
Have a look at Doctrine 2 for example. It's a big project, but when u master it, its damn awesome :)
If this is too big for you, refactor your class to not use singleton pattern implementation and/or static methods.
Here's what I suggest:
Create a Database class.
<?php
class Database {
private $db;
private $host;
private $username;
private $password;
// Should probably not put your DB credentials here, just the Databases, but its just here for this purpose
const DB_HOST = '';
const DB_USERNAME = '';
const DB_PASSWORD = '';
// Just an example of having multiple databases, so you can just Database::DB_1 when you need to use them
const DB_1 = '';
const DB_2 = '';
const DB_3 = '';
public function __construct($db = self::DB_1, $host = self::DB_HOST, $username = self::DB_USERNAME, $password = self::DB_PASSWORD) {
$this->db = $db;
$this->host = $host;
$this->username = $username;
$this->password = $password;
$this->db = $db;
}
// So if you have different databases, you can create different functions to connect to them via PDO drivers
public function connectToMySQL($db = null) {
$dsn = is_string($db) ? 'mysql:dbname='.$db.';host='$this->host : 'msql:dbname='.$this->db.';host='$this->host;
try {
return new PDO($dsn, $this->username, $this->password);
} catch (PDOException $E) {
echo 'Connection error: '.$E->getMessage();
exit();
}
}
To use this you would just:
/*
* Remeber how we defined it? you can leave the parameters blank, or pass in things
*/
$Database = new Database();
/*
* A PDO database object that connects to your database automaticaly.
* You can also passin Database::DB_2 sand stuff if you hav multiple databases.
* is a PDO object, so to use it, just look up PHP's PDO tutorials
*/
$PDO = $Database->connectToMySQL();
/*
* Then to end the connection, it's just as simple as setting it to null
*/
$PDO = null;
This way, you create 1 Database object that can generate MANY connections, it's like a Factory class.
I believe this why is most versatile, but I'm always open to suggestions as well.
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 just started doing OOP, so I apologize in advance if there is a simple solution.
Basically I need to use my $mysqli object inside a class. I've seperated it into two files.
config2.php
class Config
{
public $host = 'localhost';
public $username = '****';
public $password = '****';
public $database = '****';
function report_error($query)
{
$email = '*#hotmail.com';
$subject = 'MySQL error.';
$message = "IP: {$_SERVER['REMOTE_ADDR']} \n URL: http://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']} \n\n MySQL query: {$query} \n\n MySQL error: " . $mysqli->error();
mail($email, $subject, $message);
die('Oops, an error has occured. The administrator has been notified.');
}
}
$config = new Config();
$mysqli = new mysqli($config->host, $config->username, $config->password, $config->database);
if($mysqli->connect_error)
report_error($mysqli);
administration.php
require('includes/config2.php');
$mysqli->real_escape_string(); // Works out of scope.
class Account
{
public $username = $mysqli->real_escape_string(); // Doesn't work in scope.
public $password;
function login()
{
}
}
Thanks for the help guys, I appreciate it :).
You should pass the object to the constructor of Account and save it as a private instance variable.
Account is directly dependent on an instance of mysqli, so there is nothing wrong with making that clear by specifying it as a required parameter in the constructor. That is the only way you can make sure that whenever Account is used the mysqli object is there too. If you access it from a global state instead (by either having a static accessor or by directly accessing the global scope) you can never guarantee that it is really there.
You should encapsulate the $mysqli object and make it static
usually you would encapsulate the DB in some class called "DBConnection" or similar. And this instance should manage the real $mysqli object as singleton
in (very)short:
class Config
{
public $host = 'localhost';
[...]
public static $connectionObj
public static getConnection(){
if (!isset($this->connectionObj ){
$connectionObj = new mysqli($this->host, $config->this, $config->this, $this->database);
if($mysqli->connect_error){
report_error($mysqli);
}
}
return $this->connectionObj;
}
}
You get access to this object from everywhere:
$mysqlObj = Config.getConnection()
DISCLAIMER:
This is very short, untested code and database should not went into config class but its own database class with all SQL functions as methods, this is just for reusing your provided code
I am fairly new to object oriented programming. I made this class which connects to mysql database to be called from models. Is there any way i can include 'database.class.php'(my db class file)
in index.php, make it global and then access it from any object like so
$object = new object;
$object->dofunc();
Also another question is dofunc() expects an array for argument, how do i make this array also global so it can be accessed from ANY where!
Here is my db class
<?php
class Database {
private $db;
public function connect($config) {
if (is_array($config)) {
extract($config);
$db = mysqli_connect($host, $username, $password);
if ($db) {
echo "balbabla";
if (mysqli_select_db($db, $database)) {
}
else {
throw new exception("<br/><strong>Could not connect to $database under $host</strong>");
}
}
else {
throw new exception("<br/><strong>Could not connect to mySQL database! Please check your details</stromg>");
}
}
}
}
?>
Also this is the file that contains the array
<?php
//Configuration for the MVC Framework
$_SETTINGS = array();
//Routing settings!
//Default controller(This controller will be loaded if there is none mentioned in the URI)
$_SETTINGS['default_controller'] = 'User';
//Default method(This will be the default method run if no method is mentioned in the URI)
$_SETTINGS['default_method'] = 'Register';
//Database settings
$DB_SETTINGS['host'] = 'localhost';
$DB_SETTINGS['username'] = 'root';
$DB_SETTINGS['password'] = 'foobar';
$DB_SETTINGS['database'] = 'freelance';
?>
Thanks in advance
Is there any way i can include 'database.class.php'(my db class file) in index.php, make it global
You can, but you shouldn't.
Also another question is dofunc() expects an array for argument, how do i make this array also global so it can be accessed from ANY where!
Again you shouldn't.
Dependency injection is the way to go.
To access a global variable from within a function, use the global keyword. For example, to access $DB_SETTINGS from Database::connect(), you could do:
public function connect() {
global $DB_SETTINGS;
...
The array would then be accessible inside that function.
As for globally accessible classes, they are automatically just that. Defining a class makes it available anywhere.