Extending vs not extending a class in PHP - php

I'm new. Below is the beginning of an attempt to interface with a database. Please let me know if the syntax is not correct, it seems to work on my localhost.
I think I could have typed class Database extends Mysqli, right? which would then have made the methods of Mysqli directly accessible to Database rather than through an instance created in the class itself. Would that have been preferable to what I have done?
class Database {
#The variable that stores the database handle
public $db;
#The Database objects's datbase parameters
public $host;
public $user;
public $password;
public $database;
#creates a Database object with the required databases details
public function __construct($host, $user, $password, $database) {
$this->host = $host;
$this->user = $user;
$this->password = $password;
$this->database = $database;
}
#Stores the database handle as a var $db of the Database instance
public function connect() {
if ($this->db = new Mysqli($this->host, $this->user, $this->password, $this->database)) {
if ($this->db->connect_errno) {
echo "No connection could be made <br/>";
} else {
echo "database succesfully connected <br/>";
}
}
}
}

If your class Database represents the database handle, then it should not have it public:
#The variable that stores the database handle
public $db;
Otherwise you would not encapsulate that detail and therefore you wouldn't need your class at all.
Next to that, when you start to write classes, echo does not belong in there:
if ($this->db = new Mysqli($this->host, $this->user, $this->password, $this->database)) {
if ($this->db->connect_errno) {
echo "No connection could be made <br/>";
} else {
echo "database succesfully connected <br/>";
}
}
Because classes consists of methods returning via their return value and not via standard output. Instead you want to throw an exception here. Which is also a feature of Mysqli already, therefore, you don't need to write that error handling code your own to get started:
Turning query errors to Exceptions in MySQLi
After getting these more or less obvious ones out of the way, you're asking yourself whether or not you should inherit mysqli instead of aggregating it.
I actually can not tell you. So far the code you've shared just shows standard functionality of a mysqli therefore I would suggest to drop that class completely as the code looks superfluous. So I would say: neither. I see no reason for your Database class as you just could use mysqli instead.

Related

How many SQL-connections they are recommended in a project PHP ? What is the ideal number of SQL-connections?

I work now on a project for learning i'm a beginner, i use singelton pattern to make sure, that there is just one PDO connection to the Data Base.
I made var_dump() for all possible connections to the Mysql and I founded that there were 10 objects of pdo.
how can i found, from where come all this objects?
Are 10 objects of PDO normal?
I wanted to use just one for all the project.
my singelton
<?php
namespace App\Database;
use PDO;
use PDOException;
class DataBase
{
private static $instance;
private PDO $pdo;
private function __construct()
{
try {
$db= parse_ini_file("..//..//..//config.ini");
#$db= parse_ini_file("..//..//config.ini");
$type = $db['type'];
$host = $db['host'];
$name = $db['name'];
$user = $db['user'];
$password = $db['password'];
$this->pdo = new PDO($type . ':host=' . $host . ';dbname=' . $name, $user, $password);
}
catch (PDOException $e) {
echo "there is an error";
die();
}
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $this->pdo;
}
private function __clone() {}
public static function getInstance()
{
if (!static::$instance) {
static::$instance = new DataBase();
}
return static::$instance;
}
public function getPdo(): PDO
{
return $this->pdo;
}
}
?>
then I made a connection of the pdo like this in another place, where I need to use pdo init.
function makePdo(){
$db= DataBase::getInstance();
$pdo= $db->getPdo();
var_dump($pdo);
return $pdo;
}
Thank you
10 connections are not normal, you should have only one to one DB. Use singleton pattern for database connection:
https://gist.github.com/jonashansen229/4534794
https://phpenthusiast.com/blog/the-singleton-design-pattern-in-php
In this case, you will have one connection and always will get it instead of creating duplicates.
No it should be only one object, the best way to implment it, is to create a separate config file to store your DBMS credentials as associative array, like mysql db_name, host .. etc.
Then create a config class to get those values by creating a static get method.
and finally use this get method inside your db constructor to get the credentials.
I'm pretty sure If you do that you'll get only one instance of PDO object.

Can I save a PDO connection to $GLOBALS and use it later to ensure that connection is created once?

I just want to make sure that PDO connection is created once in order to give some optimization to the script.
The code below can become much more pretty and maintainable but here I just want to keep it as simple as possible. (i.e. using classes and constructors)
Does this code ensure that PDO connection is created once? In another words a called method should be able to retrieve the connection which is already created in index.php and use it.
May it be more optimized (increasing performance)?
Update:
I'm not talking about persistent connection.
index.php
require 'file.php';
$GLOBALS['db_connection'] = new PDO("sqlite:db.sqlite");
if(request == 'create_user')
user::create_user();
// ...
else
exit();
file.php
class user{
public static function create_user(){
$conn = $GLOBALS['db_connection']; // should not attempt to reconnect because a PDO connection is already made in index.php
$stmt = $conn->prepare("INSERT INTO table1 ...");
// ...
functions::do_sth(); // again should not attempt to reconnect because a PDO connection is already made in index.php
// ...
exit();
}
}
class functions{
public static function do_sth(){
$conn = $GLOBALS['db_connection']; // should not attempt to reconnect because a PDO connection is already made in index.php
// ...
}
}
Alternative to your code is to use the Singleton pattern.
In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance. This is useful when exactly one object is needed to coordinate actions across the system.
Example:
class Connection {
private static $instance;
public static function make($config){
try {
if(self::$instance === NULL) {
self::$instance =
new \PDO ("mysql:host=" . $config['host'] . ";
dbname=" . $config['name'],$config['username'],$config['password'],$config['options']
);
}
return self::$instance;
} catch (\PDOException $e) {
die("Database connection error: " . $e->getMessage());
}
}
}
// use
$dbConnection = Connection::make($config['database']);

Set $mysqli as a global variable for OOP

Ok,
This is sort of an involved problem, but any help or advice would be incredibly appreciated.
So I'm working with a site that (using .htaccess) redirects all traffic to a load.php. For any sql functionality, I have an abstract class that has a lot of query statements as functions that pass parameters to define the specifics of each query.
e.g.
$table->update("constraints")
I'm trying to figure out how to set the connection to the database on load.php, and then set the connection as a variable ($mysqli) that can then be referenced in my abstract query class without having to pass the parameter to every single query function call.
Again, any help or advice would be appreciated.
Here's an example of a function:
function clearTable (){
$mysqli = dbConnect::connect();
$sql = "TRUNCATE TABLE $this->tablename";
$mysqli->query($sql);
}
If I connect to the database in a construct function and set $this->mysqli and replace $mysqli = dbConnect::connect(); with $mysqli = $this->mysqli, none of the queries work. Though they work with a fresh reconnect on each call.
You should use Dependency Injection for this.
Basically it means that the class that needs the database connection doesn't create the connection, it just receives the already instasiated instance.
Example
In some init file:
// Create the db connection
$db = new Mysqli(......);
// Pass it to the query class that needs it
$queryClass = new QueryClass($db);
Then in your class file:
class QueryClass
{
protected $db;
public function __construct($db)
{
// $this->db will now be the same Mysql instance
$this->db = $db;
}
public function doSomeQuery()
{
$this->db->query(....);
}
}
A bonus for this is that you don't need to touch the QueryClass, if you ever want to start making some unit tests. You only need to pass a DB connection to a test database instead.
After looking through this a bit more, I can also create my db::connect() function to look like this:
class dbConnect {
private static $db;
private $mysqli;
private function __construct() {
$this->mysqli = new mysqli(HOST, USER, PASSWORD, DATABASE);
}
function __destruct() {
$this->mysqli->close();
}
public static function connect() {
if (self::$db == null) {
self::$db = new dbConnect();
}
return self::$db->mysqli;
}
}
and pass that as $this->mysqli in the query functions file

Multiple Singleton mysql connections using same class

I have a PHP app that uses 2 different databases. The connection is realized by a singleton mysql class. What I would like to achieve is to use the same class but to connect to another database depending on a variable stated when calling the class.
So, the code used (but not yet functional):
/ start the single class
class Singleton {
// declare two private variables
private static $_instace;
private $conn;
var $dbc = 0;
// declare private constructor class
private function __construct() {
$this->conn = mysql_connect(HOST, USER, PASS);
//die('DB State: [' . $this->dbc . ']');
if ($this->dbc) {
mysql_select_db(DB_DATABASE_PS);
} else {
mysql_select_db(DBNAME);
}
}
// create a singleton method
public static function getconnect($dbc = false) {
if (!self::$_instace) {
self::$_instace = new Singleton();
$_instace->dbc = $dbc;
} else {
$_instace->dbc = $dbc;
}
return self::$_instace;
}
}
When calling a class that uses the first database (DBNAME), it all works perfect but when trying to use the second database, the code doesn't help me at all.
The code to load the second database inside a new class is made trough this code:
public function __construct() {
$this->connect = Singleton::getconnect(true);
}
Could someone help me figure it out?
Thank you!
The problem is, you're selecting the database during the construction of the object(in __construct() method) and it's completely based on the class member variable $dbc. So the next time you want to change the database, you have to call getconnect() method like this, Singleton::getconnect(true);, and then create another object to change the database, which would eventually defeat the purpose of singleton pattern. So basically, every time you change the database you have to call getconnect() method with true and false parameter alternatively, and create a new object to change the database.
Now comes down to your problem,
how should I use it (the singleton class) to change between the databases, keeping in mind that on a single page there could be data from both databases
Use the following code snippet to implement singleton pattern and change databases using a single object.
class Singleton {
// declare two private variables
private static $instance;
private $conn;
// Since it's constructor method is private
// it prevents objects from being created from
// outside of the class
private function __construct() {}
// It creates an object if not previously created,
// opens a connection to MySQL Server
// and returns the object
public static function getInstance() {
if(!isset(self::$instance)){
self::$instance = new Singleton();
self::$instance->conn = mysql_connect(HOST, USER, PASS);
}
return self::$instance;
}
// set your database here
public function setDatabase($db){
return mysql_select_db($db, $this->conn);
}
// Execute your query here
public function executeQuery($query){
return mysql_query($query, $this->conn);
}
// Close your connection here
public function closeConnection(){
mysql_close($this->conn);
}
}
// Get an instance of Singleton class
$obj = Singleton::getInstance();
// Set database "abc"
if($obj->setDatabase("abc")){
echo "database has changed <br />";
}else{
echo "database has not changed <br />";
}
// Display the selected database
$resultset = $obj->executeQuery("SELECT DATABASE() as db");
$row=mysql_fetch_assoc($resultset);
echo $row['db'] . "<br />";
// Set database "def"
if($obj->setDatabase("def")){
echo "database has changed <br />";
}else{
echo "database has not changed <br />";
}
// Display the selected database
$resultset = $obj->executeQuery("SELECT DATABASE() as db");
$row=mysql_fetch_assoc($resultset);
echo $row['db'] . "<br />";
// close connection
$obj->closeConnection();
Output:
database has changed
abc
database has changed
def
Sidenote: Please don't use mysql_ database extensions, they were deprecated in PHP 5.5.0 and were removed in PHP 7.0.0. Use mysqli or PDO extensions instead. And this is why you shouldn't use mysql_ functions.

Using an object for database connections

I am new to OOP having this code and am having a problem creating a database connection, what could be the problem? Strangely am not getting any errors yet i cannot make any MYSQL INSERTS or SELECTS from the database because the connections have not been made
//include the file that contains variables necessary for database connection
require_once 'configurations.php';
//This is the class that will be used for the MySQL Database transactions
class MySQLDatabase
{
private $database_connection;
//constructor class
function __construct()
{
$this->open_connection();
}
public function open_connection()
{
$this->database_connection = mysql_connect(DATABASE_SERVER, DATABASE_USERNAME, DATABASE_PASSWORD);
if (!$this->database_connection)
{
//if the connection fails, return the following message and indicate the error
die("Could not connect to the MYSQL Database due to: " . mysql_error());
}
else
{
//if the connection is made to MYSQL database, then select the database being used
$database_selection = mysql_select_db(DATABASE_NAME, $this->database_connection);
//if the database to be used cannot be selected, return this error
if (!$database_selection)
{
die ("Could not select the database due to: " . mysql_error());
}
}
}//end of function open database
}//end of class MySQLDatabase
$database_transactions = new MySQLDatabase();
There are a few things I would consider...
You write function __construct()
but all the other methods and
properties are either public or
private - use public function
__construct()
Why is the method open_connection()
public? Should it be called from
"outside"? Do you want someone
to execute this method directly
from an object? Think about making it private function open_connection() -> http://de.php.net/manual/en/language.oop5.visibility.php
Why use die() in OOP? Do you really
want to output the error message to
the user? It isn't secure to do that.
It's better to throw an Exception and work with try{} and catch{} to handle an error -> http://de.php.net/manual/en/language.exceptions.php
Are you really sure you're getting no error messages at all? Show use your query method... Your code should be fine so far (at least you should get an error on screen with die() if something is not correct).

Categories