pdo connection position in php class - php

I'm using PDO now and I have a number of classes.
Every time I use a class, I don't always use its database-related functions. Sometimes I keep using a class until at the end I might do some work with the database, like save this object to DB.
So I'm currently doing something like this:
class Something
{
protected $pdo;
function connect()
{
$this->pdo = new PDO( "mysql:host=".zConfig::read('hostname').";dbname=".zConfig::read('database'), zConfig::read('username'), zConfig::read('password'));
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
/* lots of functions doing lots of non-DB things */
function saveToDB()
{ $this->connect();
$this->pdo->prepare("Some SQL that saves some stuff");
// now do some DB-related pdo work
}
}
My question is - is this reasonable? Is this the way a lot of you code?
As I see it, there are 3 options:
The way I'm doing it - connecting to the database only in those
functions that are database related. But these means each time I run a DB-related function.
Open a connection in the constructor, in this case I only open it once, but also end up opening it even when I don't need it, so I feel like sometimes I'll be creating
connections for nothing.
On the other hand, I could use a singleton database class like this:
PDO Connections - max connections
I do have up to three related objects on a page, and sometimes I do and sometimes I don't need to connect to the DB more than once on a page. which design is safer?

You should use DI, in your class to instantiate a connection, when your object is defined ex:
class foo{
public $conn;
function __construct($conn){
$this->conn = $conn;
}
function doSomething(){
}
}
Now, if you find yourself, not wanting to instanciate a connection, whenever you
are on a page/work that does not need database connection, and significantly slows your page, while trying to connect, use the PDO attribute
ATT_PERSISTENT property like:
$conn = new PDO('mysql:host=localhost;dbname=xxx', 'xxx', 'xxx',
array( PDO::ATTR_PERSISTENT => true )
);
$object = new foo($conn);
Simply, once, you open a page, and connection is establish the ATTR_PERSISTENT method will store that connection, pretty much like sessions work, and will keep feeding your page, and helping you from creating a new connection to your db, every time you refresh a page, or go on to another page. Try, it.. and you'll see how faster your pages will load.

You can just use lazy way.
protected $pdo;
function connect()
{
if ($this->pdo === null)
{
$this->pdo = new PDO( "mysql:host=".zConfig::read('hostname').";dbname=".zConfig::read('database'), zConfig::read('username'), zConfig::read('password'));
$this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
Check this question.

Related

Static Varible vs PDO::ATTR_PERSISTENT

I have a database class that I developed. But I have doubts about performance in case of load. There are two issues that I was curious about and couldn't find the answer even though I searched.
When the database connection is bound to a static variable in the class,
class DB
{
static $connect;
......
function __construct()
{
try {
self::$connect = new PDO("{$this->db_database}:host={$this->db_host};dbname={$this->db_name};charset=utf8mb4", "{$this->db_username}", "{$this->db_password}");
self::$connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
self::$connect->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, "SET NAMES utf8mb4");
} catch ( PDOException $e ){
echo '<b>ERROR: </b>'.$e->getMessage();
exit;
}
}
}
PDO::ATTR_PERSISTENT => true
Does it have an equivalent ability?
Also, I didn't fully understand the pdo permalink logic, it uses the existing connection instead of opening a separate connection for each user. But how does he use the existing link here? For example "ip address" etc.
Thank you for your help.
Let me approach the issues from a different direction.
A program should have only one connection to the database. (There are rare exceptions.) Your code, as it stands, seems to be inconsistent. It has a single ("static") connection, yet the class can be instantiated multiple times, thereby connecting multiple times. (I don't want to depend on anything "persist" to clean up the inconsistency.)
Either make the class a singleton or otherwise avoid being able to call __construct a second time. One approach goes something like this:
class DB {
private static $connect;
......
public function __construct() {
if (! self::$connect) {
self::$connect = ...
}
}
public function Fetch(...) {
self::$connect->...
return ...;
}
$con = new DB();
$data = $con->Fetch(...);
(plus suitable try/catch)
Note that that allows you to sub-class as needed.
Another approach might involve preventing the use of new:
private function __construct() { ... }
plus having some public method invoke that constructor.
Here's another approach. It can be used on an existing class that you don't want to (or can't) modify:
function GetConnection() {
static $db;
if (! $db) {
$db = new ...;
}
return $db;
}
$db = GetConnection();
$db->Fetch(...)'
As for "connection pooling", it is of limited use with MySQL. (Other products need it much more than MySQL does.) In my opinion, don't worry about such.
Do not use "auto-reconnect". If the connection dies in the middle of a transaction and is automatically restarted, then the first part of the transaction will be rolled back while the rest might get committed. That is likely to lead to data inconsistency.
Singletons, statics, globals, void*, critical sections all make me cringe. When I need such, I rush to find a way to "hide" it, even if that means writing cryptic code in some class(es).
For performance, MySQL really needs a single connection throughout the program. I compromise by hiding the connection in a "static" that serves at a "global". Then I hide that inside the class that I use to abstract the object(s).
I agree with Karwin's [now delete] Answer -- that this discussion is "much ado about nothing". MySQL performance is mostly about indexing, query formulation, and even the architecture of the application. Not about connections, common code elimination, redundant function calls, etc.

Switching from PHP's mysql extension to PDO. Extend class to reduce lines of code

So this is something I've been meaning to get to grips with for ages. Converting a few small (single-file) applications to PDO. I can use PDO, connect to a database and run queries, all working.
But each time I initialise a new PDO, I'm also having to run
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
Yeah it's only one line but one day I might need to add further stuff in there. To me it would seem better to somehow extend the PDO class in a way that can include that line so I can just start my DB connection with a single line. Creating my own class, even if only adding a single line of code at this stage, keeps me future-proofed if I ever decide to add anything else in the future.
I've found something like this...
class myPDO extends PDO {
public function __construct($dsn, $user=null, $pass=null, $options=null) {
parent::__construct($dsn, $user, $pass, $options);
$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
}
// THEN A SIMPLE 1 LINER TO CONNECT - USING TRY/CATCH AS WELL OF COURSE
$pdo_conn = new myPDO($cfg['pdo_dsn'], $cfg['pdo_user'], $cfg['pdo_pass'], $cfg['pdo_options']);
When extending the class I assume I don't actually need to re-create the constructor.
Is there a way I can integrate my $this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); into my class without re-creating the constructor function?
I'm just getting started with PHP's class syntax so this will be a really basic question for someone but it will answer a few other questions for me at the same time.
You do not need to extend from PDO here. What you want is a central place in your application that is creating the PDO object. You can then do the changes you like over time (e.g. integrating some configuration file/system) and extend then centrally.
One thing is that you create a class for that, let's call it PdoFactory:
class PdoFactory
{
/**
* #return PDO
*/
public function buildPdo() {
$pdo = new PDO($dsn = 'xyz', $user = 'abc', $pass = '', $options = '');
if ($pdoException = true) {
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return $pdo;
}
}
Usage:
$factory = new PdoFactory();
$pdo = $factory->buildPdo();
As you can see, this is very easy to use. You can even put the place where you create the PdoFactory apart from the place where you invoke the buildPdo() function.
Also this makes it more clear that you are dealing with two different things here: First creating the Pdo object (encapsulated into a class of it's own) and the Pdo object itself which is just for accessing the database.
I hope this helps.
The problem, as I see it, is that you are hard-coding a particular error level into your application. What if you're in development and you want everything? What if you decide you want to change the level for a particular application? It would be much better to keep it as a parameter you set after the fact, or, if you're bent on subclassing it, pass an error level in as a constructor argument.

PHP PDO class construction

I'm pretty new to both PDO and OOP. I'm trying to write a class that connects to a database and updates inserts and modifies it. I have several questions:
Is it good practices to connect to the database in the constructor?
Should the one class be updating, inserting, modifying and connecting or should it be split up into several classes?
Why is runQuery not working? I assume its because $pdo is defined in a different scope. How would I get this working?
If the class is include at the top of every page does that mean it will reconnect to the database every time a new page is loaded and will that cause security issues?
Apologies for the overload of questions. Thanks in advance for any answers.
<?php
class Login{
private $_username;
private $_password;
private $_host;
private $_database;
private $_driver;
//Connect to the database
function __construct($configFile){
$connectionDetails = parse_ini_file($configFile);
$this->_username = $connectionDetails['username'];
$this->_password = $connectionDetails['password'];
$this->_host = $connectionDetails['host'];
$this->_database = $connectionDetails['database'];
$this->_driver = $connectionDetails['driver'];
$pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
}
public function loginAllowed($user, $pw){
$sth = $pdo->setFetchMode(PDO::FETCH_ASSOC);
print_r($sth);
}
public function runQuery($query, $params){
$sth = $this->pdo->prepare($query);
$sth->execute($params);
}
}
Because $pdo is a local variable in your constructor and your method loginAllowed. You should make it an instance variable (private $pdo) so you can call it through $this->pdo. I also suggest to use type hinting here, give the PDO class as a parameter in the constructor.
Example
<?php
class Login {
private $pdo;
// Your other instance variables
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
// Your other methods
}
$pdo = new PDO("...");
$login = new Login($pdo);
You shouldn't bother your class with reading settings and initialising your database connection (definitely read about separation of concerns), keep it out of your class. Just give the PDO object as a parameter (I used type hinting, that way you are forced to provide an object of the PDO type). Another advantage is that you can now make sure you have only one active database connection (you can manage this in your code base), creating multiple connections is unnecessary and definitely unwanted (performance wise).
Also use require_once to include your class definition. Otherwise you will get many errors about redeclaring (and you'd want to avoid that).
Connect to the db wherever you find it most convenient. Just try to make sure there's only ONE connection. More connections to the same db is a waste of time and resources.
The class you refer to is called a model in the MVC architecture. It usually does all the operations on a given table. I see nothing wrong in using a single class for all your needs - as long as the code is readable and maintainable.
It's not working because $pdo is a local variable. In the ctor, instantiate $this->pdo instead.
Including a class is not equivalent to instantiating it. A new instance will make another connection. Including it multiple times will only give you a multiple declaration error :). Use require_once instead. If you wish to use the instance in multiple files, I strongly suggest you do a quick search regarding the Singleton pattern. Using a singleton object will ensure you always have only one instance of your model object.
Don't bother with all the random stuff, just replacethis in your construct:
$pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
with
$this->pdo = new PDO("$this->_driver:host=$this->_host;dbname=$this->_database", $this->_username, $this->_password);
and reference it as $this->pdo from now on. As simple as that!!
1) Is it good practices to connect to the database in the constructor?
No good.just connect befor query
if($this->pdo == null) {
$this->pdo = new PDO("....");
}
2) Should the one class be updating, inserting, modifying and connecting or should it be split up into several classes?
Add methods for class
3) Why is runQuery not working? I assume its because $pdo is defined in a different scope. How would I get this working?
use $this->pdo instead
4) If the class is include at the top of every page does that mean it will reconnect to the database every time a new page is loaded and will that cause security issues?
use static $pdo
then self::$pdo would be the only one connector
if(self::$pdo == null) {
self::$pdo = new PDO("....");
}

PHP OOP: Creating database class

I am making my first steps in the OOP world - please bear with me.
I know that having many ongoing mySQL connections open at the same time can be fatal for performance, so it should be a good idea to make a database class that takes this into account.
Is $this->session->write(...); going to result in a new mySQL connection being opened each time?
Or is that up to the "persistent connection" feature in mySQL?
Here's the code:
abstract class database {
function __construct() {
//mysql_connect()
}
}
class session extends database {
function write () {
// mysql_query(--.)
}
}
Is session handler some kind of specialized type of database? It is not, so don't use inheritance (a is a relationship). Session handler uses database so you should use composition (a has a relationship):
class Session {
protected $db;
public function __construct(DB $db) {
$this->db = $db;
}
public function write() {
$this->db->query(...);
}
}
$db = new DB(...);
$session = new Session($db);
Also, don't use mysql_*() functions. Use much more powerful PDO.
Returning to your question... mysql_connect() will be executed every time you create a new Database object. However in this case Session is an object of type Database so every time you write new Database() or new Session() the constructor is invoked, therefore mysql_connect() is invoked as well.
PS. mysql_connect() function won't create a new connection if specified connection already exists. Check 4th argument of this function to learn more.
mysql_query will create a new connection only if no previous mysql connection has been made. Otherwise, it will either use the connection you specify or the last connection opened with mysql_connect. http://php.net/manual/en/function.mysql-query.php
Why not
class database {
function __construct() {
//mysql_connect()
}
function write() {
//query the DB
}
}
I'm not sure of the syntax, I don't do OOP PHP. Anyway, in your structure above a new connection would be opened for each "session" instance so assuming you only create one instance of "session" you won't be openeing loads of database connections.

How do you efficiently connect to mysql in php without reconnecting on every query

I'm pretty sick of having to rewrite my code every time I learn something new about php (like the fact that mysql connections cannot be passed around in a session as a handle).
How do you implement mysql connection in your projects? A lot of people have proposed "connection pooling", but after reading the manual i'm still lost. It's like: "connection pooling is mysql_pconnect!" - me: "and...? how is that any different in reality? can you pass around a mysql_pconnect in a session? why is this seemingly mysterious aura??"
Let me explain my situation. I have a function called "query1":
function query1($query)
{
$db = new mysql(HOST,USER,PASS,DBNAME);
$result = $db->query($query);
$db->close();
return $result;
}
This is seems like a squanderous and inefficient way of querying a db (especially since you need a mysql handle for functions like mysql_real_escape_string). What is the correct form to do it? Can someone please help me?
Thank you I'd really appreciate a good honest answer.
Normally connections happen once a page load. AKA
class Database{
public function connect()
{
$this->connection = mysql_connect();
}
// This will be called at the end of the script.
public function __destruct()
{
mysql_close($this->connection);
}
public function query($query)
{
return mysql_query($query, $this->connection);
}
}
$database = new Database;
$database->connect();
$database->query("INSERT INTO TABLE (`Name`) VALUES('Chacha')");
Basically, you open the connection in the beginning of the page, close it at the end page. Then, you can make various queries during the page and don't have to do anything to the connection.
You could even do the mysql_connect in the constructor as Erik suggest.
To use the above using global variables (not suggested as it creates global state), you would do something like
Global $db;
$db = new Database;
// ... do startup stuff
function doSomething()
{
Global $db;
$db->query("Do Something");
}
Oh, and no one mentioned you don't have to pass around a parameter. Just connect
mysql_connect();
Then, mysql_query will just use the last connection no matter what the scope is.
mysql_connect();
function doSomething()
{
mysql_query("Do something");
}
Per the comments:
I think you should use mysql_pconnect() instead of mysql_connect(), because mysql_connect() doesn't use connection pooling. – nightcoder
You might want to consider whether you use mysql_connect or mysql_pconnect. However, you should still only connect once per script.
You don't need to connect to the database in every function. You need to connect to the database when the script starts running and save connection object in global state. In any function you can use that connection object to query the database. Your connection object will be recreated for every time script is executed but it will be very fast, because special connection pool is used behind the scene, so connection will be done immediately (matter of microseconds, because actually connection was not even broken, it was saved in connection pool).
Here is the example you asked for:
// this code should be executed on every page/script load:
$adoConn = ADONewConnection(...);
$adoConn->PConnect(...);
// ...
//And then in any place you can just write:
global $adoConn;
$adoConn->ExecuteNonQuery("INSERT INTO test SET Value = 'Hello, world!'");
As for your question "how do I implement connection pool". You don't. It's maintained by the server behind the scene and used if you (or the PHP library for work with PHP) use mysql_pconnect() function.
PS. If you are afraid to keep $adoConn as a global variable (I'm not) then you can create a class with a static property:
class DB
{
public static $adoConn;
}
// ...
DB::$adoConn->ExecuteNonQuery(...);

Categories