Folks,
Let me preface this by stating that I'm trying to learn OOP so rather than use one of the existing Mysqli abstraction layers out there, I wanted to write my own Class.
I have the class defined in a file, and I'm just trying to get a generic query working before I start writing specific query functions.
<?php
/* Database Config */
define('DB_NAME', 'project');
define('DB_USER', 'foo');
define('DB_PASS', 'bar');
define('DB_HOSTNAME', '127.0.0.1');
class Database {
private $host;
private $user;
private $pw;
private $db;
public $con;
public function __construct($hostname, $user, $pass, $db) {
$this->DB_HOSTNAME = $hostname;
$this->DB_USER = $user;
$this->DB_PASS = $pass;
$this->DB_NAME = $db;
}
public function connect() {
$this->con = new mysqli($this->hostname, $this->user, $this->pass, $this->db)
or die('Database unavailable');
$this->con->set_charset ('utf8');
}
public function query($sql) {
$stmt = $this->con->query($sql);
}
}
// Create a single global instance of the database class
global $DB;
$DB = new Database();
?>
Then I created a simple test.php containing:
<?php
include_once("include/config.inc");
if ($DB) {
$sql = "select user_login, user_name from users where 1 order by user_name, user_login";
$stmt = $DB->query($sql) or die($DB->errno.__LINE__);
$result = $stmt->fetch_array(MYSQLI_ASSOC);
var_dump($result);
}
else die('Database Unavailable');
?>
When I call that page I get
Fatal error: Call to a member function query() on a non-object in /www/htdocs/project/include/db.class.php on line 33
I'm not getting a die from the test page, so I believe it can reach the database, and I know the table holds data and the query works because if I switch to non Class based DB definition I get an array with expected data.
So I'm pretty sure it's a problem I created in the Class, I just can't figure out what it is. Advice please?
Seems your object wasn't created
this is your construct. It means when you create object you need to specify parameters
public function __construct($hostname, $user, $pass, $db)
Do it like this
$DB = new Database('hostname', 'dbuser', 'dbpass', 'db');
Your class is initialized fine, that's not the issue. The issue is that it can't find the query function on con, since you're not calling connect before you call query.
You should add a line inside your query function to call connect if con doesn't yet exist or isn't active, so you don't have to remember to call it before calling query.
Related
I think I've a problem in understanding how OOP works. I already changed the code that it works, but it isn't the propper way I think. Following scenario (No, I'm not creating a userlogin by myself, its really just for local dev. to understand OOP better):
I've a database.php file:
class Database {
/* Properties */
private $conn;
private $dsn = 'mysql:dbname=test;host=127.0.0.1';
private $user = 'root';
private $password = '';
/* Creates database connection */
public function __construct() {
try {
$this->conn = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "";
die();
}
return $this->conn;
}
}
So in this class I'm creating a database connection and I return the connection (object?)
Then I have a second class, the famous User class (actually I'm not using autoload, but I know about it):
include "database.php";
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct() {
$this->conn = new Database();
}
/* Login a user */
public function login() {
$stmt = $this->conn->prepare("SELECT username, usermail FROM user");
if($stmt->execute()) {
while($rows = $stmt->fetch()) {
$fetch[] = $rows;
}
return $fetch;
}
else {
return false;
}
}
}
So thatare my two classes. Nothing big, as you see. Now, don't get confued about the function name login - Actually I just try to select some usernames and usermails from database and displaying them. I try to achieve this by:
$user = new User();
$list = $user->login();
foreach($list as $test) {
echo $test["username"];
}
And here comes the problem. When I execute this code, I get the following error message:
Uncaught Error: Call to undefined method Database::prepare()
And I'm not sure that I really understand what causes this error.
The code works well when I change the following things:
Change $conn in database.php to public instead of private (I think thats bad...? But when its private, I can only execute querys inside of the Database class, I'm right? So should I put all these querys in the Database class? I think that's bad, because in a big project it will get become really big..)
And the second change I've to do is:
Change $this->conn->prepare to $this->conn->conn->prepare in the user.php file. And here I've really no Idea why.
I mean, in the constructor of the user.php I've a $this->conn = new Database() and since new Database will return me the connection object from DB class, I really don't know why there have to be a second conn->
Do not create classes such as your Database class as it's rather useless. It would make sense to create a database wrapper if it adds some extra functionality to PDO. But given its current code, better to use vanilla PDO instead.
Create a single $db instance from either vanilla PDO or your database class.
Pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
user.php
<?php
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct(\PDO $pdo) {
$this->conn = $pdo;
}
/* List all users */
public function getUsers() {
return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
}
}
app.php
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();
foreach($list as $test) {
echo $test["username"],"\n";
}
output:
username_foo
username_bar
username_baz
Check out my (The only proper) PDO tutorial for more PDO details.
I think I've a problem in understanding how OOP works. I already changed the code that it works, but it isn't the propper way I think. Following scenario (No, I'm not creating a userlogin by myself, its really just for local dev. to understand OOP better):
I've a database.php file:
class Database {
/* Properties */
private $conn;
private $dsn = 'mysql:dbname=test;host=127.0.0.1';
private $user = 'root';
private $password = '';
/* Creates database connection */
public function __construct() {
try {
$this->conn = new PDO($this->dsn, $this->user, $this->password);
} catch (PDOException $e) {
print "Error!: " . $e->getMessage() . "";
die();
}
return $this->conn;
}
}
So in this class I'm creating a database connection and I return the connection (object?)
Then I have a second class, the famous User class (actually I'm not using autoload, but I know about it):
include "database.php";
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct() {
$this->conn = new Database();
}
/* Login a user */
public function login() {
$stmt = $this->conn->prepare("SELECT username, usermail FROM user");
if($stmt->execute()) {
while($rows = $stmt->fetch()) {
$fetch[] = $rows;
}
return $fetch;
}
else {
return false;
}
}
}
So thatare my two classes. Nothing big, as you see. Now, don't get confued about the function name login - Actually I just try to select some usernames and usermails from database and displaying them. I try to achieve this by:
$user = new User();
$list = $user->login();
foreach($list as $test) {
echo $test["username"];
}
And here comes the problem. When I execute this code, I get the following error message:
Uncaught Error: Call to undefined method Database::prepare()
And I'm not sure that I really understand what causes this error.
The code works well when I change the following things:
Change $conn in database.php to public instead of private (I think thats bad...? But when its private, I can only execute querys inside of the Database class, I'm right? So should I put all these querys in the Database class? I think that's bad, because in a big project it will get become really big..)
And the second change I've to do is:
Change $this->conn->prepare to $this->conn->conn->prepare in the user.php file. And here I've really no Idea why.
I mean, in the constructor of the user.php I've a $this->conn = new Database() and since new Database will return me the connection object from DB class, I really don't know why there have to be a second conn->
Do not create classes such as your Database class as it's rather useless. It would make sense to create a database wrapper if it adds some extra functionality to PDO. But given its current code, better to use vanilla PDO instead.
Create a single $db instance from either vanilla PDO or your database class.
Pass it as a constructor parameter into every class that needs a database connection
database.php:
<?php
$host = '127.0.0.1';
$db = 'test';
$user = 'root';
$pass = '';
$charset = 'utf8';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new \PDO($dsn, $user, $pass, $opt);
user.php
<?php
class User {
/* Properties */
private $conn;
/* Get database access */
public function __construct(\PDO $pdo) {
$this->conn = $pdo;
}
/* List all users */
public function getUsers() {
return $this->conn->query("SELECT username, usermail FROM user")->fetchAll();
}
}
app.php
include 'database.php';
$user = new User($pdo);
$list = $user->getUsers();
foreach($list as $test) {
echo $test["username"],"\n";
}
output:
username_foo
username_bar
username_baz
Check out my (The only proper) PDO tutorial for more PDO details.
DbConnect.php
<?php
/**
* Handling database connection
*/
include_once ('Config.php');
class DbConnect {
private $conn;
function __construct() {
}
/**
* Establishing database connection
* #return database connection handler
*/
function connect() {
// Connecting to mysql database
$this->conn = new mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Check for database connection error
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit;
}
// returing connection resource
return $this->conn;
}
}
class DbHandler {
private $conn;
function __construct() {
// opening db connection
$db = new DbConnect();
$this->conn = $db->connect();
}}
?>
config.php
<?php
/**
* Database configuration
*/
define('DB_USERNAME', 'medma');
define('DB_PASSWORD', 'medma');
define('DB_HOST', 'localhost');
define('DB_NAME', 'medma_sameer');
/**
* MSG91 configuration
*/
define('MSG91_AUTH_KEY', "130558AmTMgKzL582187bb");
// sender id should 6 character long
define('MSG91_SENDER_ID', 'MEDMA1');
define('USER_CREATED_SUCCESSFULLY', 0);
define('USER_CREATE_FAILED', 1);
define('USER_ALREADY_EXISTED', 2);
?>
Please tell me what could be the problem though i have posted before Not able to hit api to verify otp ( Used Volley)
but when i started testing each php file on my localhost folder where i have mounted i got stuck with the very initial step which is database connection the code i wrote above doesn't show anything except blank
There are 2 problems here that could cause the page to be blank:
The first is that you don't actually output anything in your script, at least not in the code you have posted.
The bigger problem is that this is probably wrong as you don't seem to be inside a method / class:
$db = new DbConnect();
$this->conn = $db->connect();
$this is defined in the scope of a method so using it like you are doing would lead to a fatal error:
Fatal error: Using $this when not in object context in ...
As a side-note: If you want to show the contents of a variable, you should use var_dump() instead of echo because the last only gives any meaningfull output for numbers and strings; not for database connections.
First of all you bad invoke a connection here
$db = new DbConnect();
$this->conn = $db->connect();
You can not access property conn in this scope (outside of a class) this way
You can do this using $db->conn. However in this situation you can't access it aswell as it is a private
If you would like to do this using your class you can try
$db = new DbConnect();
$conn = $db->connect();
and under $conn u have a db connection.
#edit:
Maybe try use this
<?php
include_once ('Config.php');
/**
* Handling database connection
*/
class DbConnect {
private static $_instance; //The single instance
private $_conn;
public static function getInstance() {
if(!self::$_instance) { // If no instance then make one
self::$_instance = new self();
}
return self::$_instance;
}
private function __construct() {
// Connecting to mysql database
$this->_conn = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);
// Check for database connection error
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit;
}
}
// Get connection
function getConnection() {
return $this->_conn;
}
}
To make a connection to database you can do that
$db = DbConnect::getInstance();
$conn = $db->getConnection();
$query= "SELECT foo FROM .....";
$result = $conn->query($query);
So, I'm in the middle of writing a web application for one of my clients, and I've decided to keep the database connection in a class. The following code is what I have:
class databaseConnection {
private $hostname = 'hn.app.dev';
private $username = 'root';
private $password = '';
private $database = 'hn_app_dev';
public function connect() {
$host = mysqli_connect($this->hostname, $this->username, $this->password);
if ($host) {
$connection = mysqli_select_db($host, $this->database);
if (!$connection) {
die('An error occured while trying to connect to the database.');
}
return $connection;
}
}
}
I am using the standard PHP function of mysqli_query to send queries to the database. I am using the following to send queries to the database:
function fetch_from_db($query) {
$connection = new databaseConnection();
$query = mysqli_query($connection->$connection, 'QUERY');
}
I'm new to using classes in my code. I'm still learning, as we all are. I've checked about but cannot find a fix for my issue. I know what the issue is: it's an issue with the class being an object, and something to do with fetching the returned $connection variable from it.
How can I fix this issue so that I can connect correctly to my database? Also, could anyone point me in the direction of some documentation that I could learn the fix so I can tackle this in future.
Thank you!
There are a lot of different ways you could write a object to handle connections and queries to the database.
What matters most is what your trying to achieve.
I would think these would be a few features you would like to have.
Single Connection
Runs SQL and returns mysqli results.
Access to the connection for escaping values.
It looks like you want to store your credentials within the object it self. ( I would suggest passing these in as a value in __construct()
These are a few basic features, that could easily be expanded apon.
class databaseConnection {
//private $hostname = 'hn.app.dev';
//private $username = 'root';
//private $password = '';
//private $database = 'hn_app_dev';
private $connection; // this is where the object will store the connection for other methods to access it
public function __construct($host, $username, $password, $database)
//public function connect() {
$this->connection = mysqli_connect($host, $username, $password);
if ($host) {
$this->connection->select_db($database);
if (!$this->connection) {
die('An error occured while trying to connect to the database.');
}
return $connection;
}
}
// this is so databaseConnection $db can access the connection for escaping MySQLi SQL
public function connection(){
return $this->connection;
}
function fetch_from_db($query) {
//$connection = new databaseConnection(); // I don't believe you really want to create a instance of this object inside of itself
//$query = mysqli_query($connection->$connection, 'QUERY');
$query = $this->connection->query($query); // we will use the object oriented style instead of the above procedural line
return $query; // return the results to the $results var in the bottom example
}
// this is a magic function that is called when the object is destroyed, so we will close the connection to avoid to many connections
function __destruct(){
$this->connection()->close();
}
}
// make a new datbaseConnection class with specific credentials
$db = new databaseConnection('localhost', 'someuser', 'somepass', 'somedb');
$sql = 'SELECT * FROM tableName LIMIT 100';
// call the fetch_from_db function from the new databaseConnection $db
$results = $db->fetch_from_db($sql);
// print the results
while($result = $results->fetch_assoc()){
print_r($result); // print_r on each row selected from db
}
You can learn more about OOP and PHP Objects in the Manual and there are many tutorials available online about specifically classes to manage database connections and queries.
http://php.net/manual/en/language.oop5.php
Hope this helps!
If you're going to keep it in a class, you never call the connect() function. But if you want it connected when you initiate the class, change the connect() function to __construct() and remove the return and assign it to a public variable.
class databaseConnection {
private $hostname = 'hn.app.dev';
private $username = 'root';
private $password = '';
private $database = 'hn_app_dev';
public $connection;
public function __construct() {
$host = mysqli_connect($this->hostname, $this->username, $this->password);
if ($host) {
$connection = mysqli_select_db($host, $this->database);
if (!$connection) {
die('An error occured while trying to connect to the database.');
}
$this->connection = $host;
}
}
}
After that, you can get the database connection in your function like:
function fetch_from_db($query) {
$connection = new databaseConnection();
$query = mysqli_query($connection->connection, 'QUERY');
}
Now, after having said all that, you don't want to create a new instance in every function to access the database. So possibly making it static and create an init() function of sorts so it takes less memory in the overall application.
For class documentation PHP's Classes/Objects page will help. Specifically the 'Examples' link.
<?php
class databaseConnection {
private $hostname = 'localhost';
private $username = 'root';
private $password = '';
private $database = 'onlinylh_sggsfaculty';
public function connect() {
$host = mysqli_connect($this->hostname, $this->username, $this->password,$this->database);
if ($host) {
return $host;
}
else{
echo "Error";
}
}
}
function fetch_from_db($query) {
$conn = new databaseConnection();
$r = mysqli_query($conn->connect(), $query);
}
fetch_from_db()
?>
This Worked For me.
This question already has an answer here:
Using MySQLi from another class in PHP
(1 answer)
Closed 2 years ago.
I hope someone can help me with my small problem but I cannot figure it out. What I want to achieve is having one database.php file that connects to the database each time I call it. And then I want to be able to grab results, insert results etc in other files, but without having to have a seperate connect to the database line in those files.
What I have right now, is my database connection class:
<?php
$db_host = 'localhost';
$db_user = 'dbusername';
$db_pass = 'dbpassword';
$db_name = 'dbname';
class database {
public $mysqli;
public function connect($db_host, $db_user, $db_pass, $db_name)
{
$this->mysqli = new mysqli($db_host, $db_user, $db_pass, $db_name);
if ($this->mysqli->connect_errno)
{
return "An error occured while connecting to the database";
}
}
}
?>
Now when I include this file and setup a connection like so:
$whatever = new database();
I want to be able to perform some database actions with some functions in other classes like so:
require_once("whatever.class.php");
$test = new myclass();
$update = $test->updataDatabase();
And in my "whatever.class.php" file I have the following function:
public function grabResult($table, $where, $field)
{
$result = 'SELECT * FROM '.$table.' WHERE '.$where.' = '.$field;
$query = $this->mysqli->query($result);
And whatever I try, I always get the following error:
Call to a member function query() on a non-object in /home/etc/public_html/whatever.class.php on line 5
Basically what my question is, I want to be able to use "$this->mysqli" in another class without having to set up the database connection again in that class. I just want to include the database.class.php file and then connect plus being able to use $this->mysqli.
From another page I found this:
$newConnection = new database;
$newConnection->connect($db_host, $db_user, $db_pass, $db_name);
$mysqli = $newConnection->mysqli;
But that didn't do the trick. Same as the following, did not work:
$mysqli = new mysqli($db_host, $db_user, $db_password, $db_name);
public function __construct($mysqli)
{
$this->mysqli = $mysqli;
}
I have also tried extending the "myclass" from database, with no luck, I tried using "::parent", also without any luck. Any help is greatly appreciated since I been struggling with this for a few days now.
I think you have at least 3 ways to do this... (Maybe there are more ways)
databasde.php (with class) needs to be included first for following steps
1: The first one is to extend the dbclass to your class like
class myclass extends database {
public function myclass(){
parent::__construct();
//....
}
}
than you have all functions and vars in your myclass
2: The second way is
require_once(database.php);
class myclass {
private $db;
public function myclass(){ /* the constructor */
$this->db = new database();
}
public function grabResult($table, $where, $field)
{
$result = "SELECT * FROM {$table} WHERE {$where}={$field}";
return $db->mysqli->query($result);
}
}
3: The third way is
class myclass{
private $db;
public function myclass(){
$this->db = false;
}
public function setupDBHandler($dbHwNd){
$this->db = $dbHwNd;
}
public function grabResult($table, $where, $field)
{
if($this->db){
$result = "SELECT * FROM {$table} WHERE {$where}={$field}";
return $db->mysqli->query($result);
}
else{
return "Setup DBHandler first.";
}
}
}