PHP: Making an object available to several functions - php

A beginner question: I don't know how best to structure this bit of code, but basically it goes like this (pseudo code time):
if (form = submitted) {
submitted();
}
else {
printForm();
}
function submitted() {
process data from form;
if(errors = found) {
print warnings;
printForm();
} else {
submit to database;
}
}
function printForm() {
print form with databound elements;
}
I use the following bit of code to create a User object, but it seems weird to call it twice -- once in submitted() and once in printForm(), especially since submitted() calls printForm() if errors are found.
Unfortunately database access is required for processing the data from the form (checking for existing email address, etc), so I have to call the following bit of code in both submitted() and printForm()...
try {
$db = new Database();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($db);
}
catch (PDOException $e) {
echo "<p>Error connecting to database: </p>".$e->getMessage();
}
But my instincts tell me that this is bad. Is it? If so, how should I fix it?

Use dependency injection:
function submitted(Database $db, User $user) {
// ...
}
function printForm(Database $db, User $user) {
// ...
}
try {
$db = new Database();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($db);
}
catch (PDOException $e) {
echo "<p>Error connecting to database: </p>".$e->getMessage();
}
submitted($db, $user);
printForm($db, $user);
Of course, it's better to use OOP, as then you wouldn't have to inject the dependencies into every single function:
class Foo {
protected $db;
protected $user;
public function __construct(Database $db, User $user) {
$this->db = $db;
$this->user = $user;
}
public function submitted() {
// use $this->db and $this->user here
}
public function printForm() {
// use $this->db and $this->user here
}
}
try {
$db = new Database();
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = new User($db);
$foo = new Foo($db, $user);
}
catch (PDOException $e) {
echo "<p>Error connecting to database: </p>".$e->getMessage();
}
$foo->submitted();
$foo->printForm();

There are several ways of making this better...
One would be to initialize $user before the function calls and inject it into each function (dependency injection).
Another way would be to make a singleton of the user instance (although I could see this leading to problems down the road) and retrieve the instance in the function using something like User::instance().
Dependency injection is better in my opinion because it makes your functions easier to test.
Now, on to the rest of the code:
It's typically not good practice to echo anything within a function or class method. You should be returning data instead and handling it outside the function.
Your db instantiation should probably go in a bootstrap file that's included at the top of every script. It's also probably better if your script handles the connection error gracefully (let the user know something went wrong, send yourself an email, stop the rest of the script execution) if the connection fails rather than simply echo'ing an error message.

Although the Singleton pattern is considered to be evil in some cases, it seems that in PHP (with a separate worker process for each request) and in your case it is the easiest way to implement what you want.
So that you have the instance of User who initiated the request available in any script on any page, and you have to initialize the $user object only in one place per project (not in one per script as you were wanting to do).

Related

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']);

Best way to implement database connection in php

I don't know my method is correct for connecting to the database in php.
Here is the method i am used.
1.created a db_functions.php file.
db_functions.php
/*----for connecting db----*/
function db_connect(){
$connect=new PDO('mysql:host=localhost;dbname=keralalotteryapp','root','');
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $connect;
}
function get_student_data(){
$con=db_connect();
//rest of my query
}
function get_marks($id){
$con=db_connect();
//rest of my query
}
2.In every my page i've included this and call the functions like this way
<?php
require 'db_functions.php';
get_student_data();
get_marks($id);
?>
But everytime call the functions get_student_data() and get_marks() it will again call the db_connect function.
So this is right way to do this?
Create a connection class in a Connection.php file :-
class Connection{
public static $PDO =null;
public static function getConnectionInstance()
{
try{
$PDO = new PDO('mysql:host=localhost;dbname=keralalotteryapp','root','');
return $PDO;
}catch(PDOException $e)
{
die($e->getMessage());
}
}
}
or use this class any other php file like that :-
require_once './Connection.php';
function __construct() {
$this->dbh = Connection::getConnectionInstance();
}
create construct or call static method of connection call
There are many ways to manage database connections, I've seen a global connection object, I've seen some people do connection factories, at the end of the day it really comes down to your needs in your specific application.
That being said, if you have the support for it, I have always been a fan of a closure-based setup as I find it becomes easy to write clean code.
function execute_in_db_context($callback) {
$connect=new PDO('mysql:host=localhost;dbname=keralalotteryapp','root','');
$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$callback($connect);
$connect=null; //cleanup because we can
}
execute_in_db_context(function ($db_connection) {
//blah blah
});

Extending vs not extending a class in 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.

Making a databaseDo() function for hooking PDO queries

So I started this tutorial as an intro to the PHP PDO. Up until now I've only worked with basic mysql_* type queries.
I've noticed that, throughout the tutorial, the connect -> do action -> disconnect pattern is repeated, and only the do action part ever changes.
In a real-world setting, would it be a good idea to eliminate repetition by creating a function into which queries can be passed?
For example:
a function for handling queries:
<?php
function databaseDo($action) {
$db_hostname = 'localhost';
$db_username = 'root';
$db_password = 'root';
try {
// Establish DB connection
$dbh = new PDO("mysql:host=$hostname;dbname=mysql",
$db_username, $db_password);
echo 'Connected to database';
// Do something
$action($dbh); // <- here goes whatever action we wish to perform
// Close connection
$dbh = null;
}
catch(PDOException $e) {
echo $e->getMessage();
}
?>
Then, suppose I want to perform the action in the first example of the PDO tutorial, I would set it like this:
<?php
// Define action
$insert = function($dbh) {
$query = "INSERT INTO animals(animal_type, animal_name)
VALUES ('kiwi', 'troy')";
$exec = $dbh->exec($query);
echo $exec;
};
// Perform action
databaseDo($insert);
?>
Scope of $dbh
I am using $dbh as an argument. Is this the proper way of passing a variable to a function like this without making it global?
Yes it is a great idea
A suggestion would be making a database helper class that uses the singleton pattern.. Something like
abstract class DB
{
protected static $instance;
protected $db;
protected static $host = 'host';
protected static $user = 'user';
protected static $pass = 'pass';
protected static $database;
public static function getInstance()
{
if (!isset(self::$instance)) self::$instance = new static();
return self::$instance;
}
public static function doStatement($statement, array $parameters)
{
$handler = self::sql()->prepare($statement);
$handler->closeCursor();
$handler->execute($parameters);
return $handler;
}
protected function __construct()
{
$this->db = new PDO(sprintf('mysql:host=%s;dbname=%s', static::$host, static::$database), static::$user, static::$pass);
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
}
public static function db()
{
return static::getInstance()->db;
}
}
class Main extends DB
{
protected static $database = 'db';
}
to use it
$db = Main::getInstance();
$results = $db::doStatement('SELECT * FROM table WHERE id = :id', array(':id' => 5));
Now this is just very basic, and much more would need to be added (Exception handling, more/better helper methods, etc) but I have used something like this in many projects.
While avoidance of repetition (DRY) is a principle that should always factor into your coding decisions, it should be achieved without violating another important principle, which is the separation of concerns (SoC, see also SRP). Your example, databaseDo($action), is dual-purpose: it (1) instantiates a database connection and (2) it executes a query.
Now, you may say, 'Yes! That is just what I want! Kill two birds with one stone!', and your reason for saying so would be understandable. However, mixing responsibilities can become problematic because, when you have to make changes to the way in which one responsibility is handled, you will likely also have to make changes to the way the other responsibility is handled.
Imagine you were, at some point down the road, required to support two database connections instead of just one. Suppose one of the two databases supports transactions on tables for which the other does not. Your databaseDo() function will first have to negotiate to which database to connect, and then, in order to safely execute the 'do' action, some transaction support testing will be required. It would look something like this:
$context = 'production'; // but it could equally be 'development'
function databaseDo($action) {
$db_hostname = ($context == 'production') ? 'http://remotehost.com' : 'localhost';
$db_username = ($context == 'production') ? 'apache' : 'root';
$pass = ($context == 'production') ? 'productionpassword' : 'developmentpassword';
try {
$dbh = new PDO("mysql:host=$db_hostname;dbname=mysql", $db_username, $db_password);
echo 'Connected to database';
if($context == 'production') {
// ... some complicated logic to determine whether the production db
// will support your query, then execute it if so, exit if not ...
}
if($context == 'development') {
// ... some more complicated logic for testing and querying the
// development db ...
}
$dbh = null;
} catch(PDOException $e) {
echo $e->getMessage();
}
}
Additional requirements for handling one responsibility will add complexity to the handling of the second responsibility, and this function will become more and more difficult to maintain.
A better approach to DRY in this scenario would be to handle database connection management in one component, such as within a context-aware singleton class instance (a common approach), and the query handling in another component. Thus, your query function would not necessarily have to change on account of a change in database connection handling. The tutorial to which you referred has instructions for creating and using such a singleton instance.

use an object previously declared in an other class

This is my general php page:
<?php
require_once('includes.php');
require_once('cms.class.php');
.....
rest of the page
?>
in includes.php an pro object called $db is initiated which I want to use in the class specified in the cms.class.php
includes.php:
$db = new PDO('mysql:host=localhost;dbname=xxxxx','xxxxx','xxxxxx');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
How can I use this database object in my classes without having multiple places where my credentials are stored?
You need want a dependency manager or a bootstrapper or whatever you want to call it.
class Dependency_Manager {
private $db;
public function __construct($settings) {
$this->db = new PDO('mysql:host=localhost;dbname=' . settings["dbname"],settings["username"],$setings["password"]);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
}
public function getDB() {
return $db;
}
}
class CMS {
public function __construct(PDO $db) {
/* .. */
}
}
$setting = array(/* etc */);
$dm = new Dependency_Manager($settings);
$cms = new CMS($dm->getDB());
This approach scales very well and can handle any dependecy. It also aims to put all the settings in one place so you don't have configuration settings littered everywhere. The $dm is the only one who knows the settings, if you need to construct something based on the settings, put it in the $dm.
There are 2 ways that you could go about this.
The first way, injection, is growing in popularity. Injection means you would supply $db to your class. You could do something like this.
Injection:
class CMS_class {
protected static $db;
public function __construct($db) {
if ( ! isset(self::$db))
self::$db = $db;
}
public function __get($name) {
if ($name === 'db')
return self::$db;
}
}
Now when you construct the CMS class you pass it the $db variable which is accessible via ->db, but there is only one instance.
The second method would be to call it globally in every function you use it.
Global:
class CMS_class {
function hello_world() {
global $db;
var_dump($db);
}
}
This way is losing popularity because globals are generally frowned upon and you will have to declare it in every function that you need $db.
There are other good answers out there that relate to your question.
How can I use "Dependency Injection" in simple php functions, and should I bother?

Categories