I've got a 'best practice' question about using PDO. I'm trying to finally get into object-oriented development and away from the PHP habits I developed ten years ago.
My normal method of development was to open a DB connection at the beginning of a script/page, then do a bunch of mysql_query calls as needed (mostly SELECT and INSERT). I'm using PDO for the first time, and it looks like the practice here is to create distinct PDO objects for each query/transaction. These seems like it would create multiple connections to the same DB during a string, which seems like a lot of unnecessary overhead.
Is my read on this totally wrong?
My apologies if this is covered somewhere I missed. I did look through StackOverflow, php.net, and a PHP 5.3 book I have.
No, you should not create multiple instances of PDO in that case. Just create 1 instance and use PDO::query() on it. For example:
$pdo = new PDO(...);
/* ... */
$pdo->query("SELECT * FROM table1");
/* ... */
$pdo->query("SELECT * FROM table2");
/* ... etc ... */
If the query contains parameters, then prefer using PDO::prepare() and PDOStatement::execute() instead of PDO::query(). You can find an example in the documentation for PDO::prepare().
The PDO Object stores the connection in which the queries are carried out. Normally, you only need one of those.
While there are cases where 2 connections might be convinient (When connecting to entirely different databases for instance), you generally only need one instance of the PDO class.
What you will have multiple instances of, is the PDOStatement class. Which stores the query statements themselves (as well as the results). So for every query you will have a single PDOStatement instance.
yes, you initially connect to the database by creating an instance of the PDO object. But you use this object to run queries with and the results are packed into another class.
So you mainly have several classes with your query results, but just one connection to the database which runs the queries.
Related
My web project has a class called DB_CONNECTOR where all the functions are bundled that interact with the mysql database. These would be functions like get_user(), add_user(), change_user_attribute() and many more. In each of these functions a sql query is executed and as is good practice, I use prepared statements (with named parameters).
Currently the connection to the database is established in the constructor of the class and also all the statements are prepared there. I thought this would be a good idea, so the statements are all immediatly ready for execution.
Now I realized that my use case is often to create a db_connector object, execute one or maybe two functions and then the objects lifecycle ends and at a later step a new one might be constructed (or not). So, I'm not so sure anymore if it smart to put the prepared statements in the constructor as it is forseeable that I will end up with at least 20 or likely more prepared statements.
So my question is:
is it a good idea to prepare all the statements in the constructor even if only one or two are used?
Or should I prepare them in the functions right before execution to avoid stressing the db with unneeded preparations?
This answer is based in both my experience and humble opinion, but I'll try to elaborate my arguments so it isn't just some random guy's opinion.
I don't think the database connection must be the core object in your application, let alone the only one. It'd expect to see an entirely different class for the user, so you can later have further classes for everything else. Otherwise, your application will eventually consist of a single class in a 5000 line file and your class will not be suitable to track entity data at instance level and you'll need to pass variables around in method calls. That's pretty much procedural code in OOP dress.
Also, I don't that making your User class inherits from Database (something pretty frequent nonetheless) is practical at all. Interlacing the database connection and the business logic objects doesn't really simplify application design and actually makes some parts harder.
The design of the database layer itself is pretty much standardised:
One connection per application (or more... you may need to connect to several sources!)
One statement per query.
This is exactly how PDO works.
Given that, it's easier to make the database classes just one more dependency of your entities rather than their grandparent. The injection of this dependency can be done by different means:
Make it a class property:
public function __construct(\PDO $connection)
{
$this->connection = $connection;
}
Pass it to the methods they actually needed (if not many of them):
public function getOrders(\PDO $connection)
{
$stmt = $connection->prepare('SELECT ...');
}
... or use one of those fancy dependency injection containers you can find at Packagist.
Be aware that there're also object-relational mapping (ORM), active record pattern... Those are entirely different families of solutions which may suit your needs or not depending on your use case, but not what I'm describing here.
Said that, it becomes obvious that you prepare the statements at the exact point where you need them. This design doesn't even allow otherwise ;-)
I'm flowing this article to create Database Iterator. I've similar tables and records. But when I executing I'm getting blank page. I think issue on $data = new DbRowIterator($stmt);, It's not returning proper iterator to run accept method in FilterIterator class. I'm using laravel
This article is a hoax. It claims that offered technique would speed up database calls with PDO, but in fact it slows them down significantly.
Premises on which it is grounded are also wrong. PDOStatement is already traversable, you don't need no tricks to iterate over PDOStatement using foreach.
The benchmarking section (as it often happens) is a blatant swindle. The guy is comparing fetchAll(), which obviously consumes a lot of time/memory, with fetching a single row at a time. And even this way his timing is much worse than with a proper solution.
The guy who wrote this article knows no PDO and - worse yet - no SQL.
Everything he invented already exists in PDO and SQL:
PDOStatement is already traversable. No need to reinvent the wheel.
The most important part: filtering has to be done in SQL, not in PHP. That's a textbook rule. If you need only 63992 out of 250000 records, you should select only 63992 in the first place. And if you ask a database to select the records for you, it will be incomparable faster.
So, to get everything this guy wrote with such effort, you need only few lines with PDO
$period = date_create("last_week")->format('Y-m-d 00:00:00');
$sql = 'SELECT * FROM `gen_contact` WHERE contact_modified > ? ORDER BY `contact_modified` DESC';
$stmt = $pdo->prepare($sql);
$stmt->execute([$period]);
foreach ($stmt as $row) {
echo sprintf(
'%s (%s)| modified %s',
$row->contact_name,
$row->contact_email,
$row->contact_modified
) . PHP_EOL;
}
And this code will be a multitude times faster as it does the filtering on the database level, instead of fetching the whole table and then filtering on PHP side.
As of the error you get, just set PDO in exception mode and watch for the regular PHP errors.
PDOStatement is not iterable, it's traversable:
It doesn't implements the \Iterable interface but the \Traversable interface, meaning it can be used in a foreach but you can't iterate manually over it because it doesn't expose it's inner behavior.
I don't think this makes much difference in the present case but there is still a major difference between the two interfaces.
I stumbled upon this question looking for a way to properly iterate over a PDOStatement (without using a foreach) and the article mentioned, although pretty clumsy looks actually fine to me.
As #VincentChalnot said - PDO doesn't return instances of the Iterable class, but it does return Traversable's, and it turns out that PHP provides an Iterator for Traversable objects - the IteratorIterator (http://php.net/manual/en/class.iteratoriterator.php).
So if you want to use any of PHP's built in Iterator classes, for example the CachingIterator, with a PDOStatement then you would do it like this:
$iterator = new CachingIterator(new IteratorIterator($stmt));
I'm messing around with an example site from teamtreehouse's PHP/MySQL project... In their 'model' code, they have all DB calls inside functions inside a file called products.php.. each of these functions will create a new PDO object by importing an include file.. for example:
function get_products_recent() {
require(ROOT_PATH . "inc/database.php"); //this instantiates a new PDO object called $db
try {
$results = $db->query("
SELECT name, price, img, sku, paypal
FROM products
ORDER BY sku DESC
LIMIT 4");
} catch (Exception $e) {
echo "Data could not be retrieved from the database. get_products_recent";
exit;
}
$recent = $results->fetchAll(PDO::FETCH_ASSOC);
$recent = array_reverse($recent);
return $recent;
}
But I was finding the db queries were slowing down page loads significantly..
After some googling I found the PDO::ATTR_PERSISTENT => true attribute that can be added to the PDO constructor... and that has sped up the pages loads back to 'normal'..
But is this wrong/inefficient practice for real-world scenarios..? is there a better way to be opening and using the PDO object rather than creating a new PDO object inside every function call that makes a db call?
Yes, you are doing it wrong.
Yes, you have to declare single PDO object at the beginning of the file and use it throughout the whole application. This is a very basic rule, that have to be followed despite any circumstances. This is not the "best", this is the only acceptable design.
In fact, you are practically killing your your DB server, opening as many connections as many times PDO object is created. And time consumed for the connection is not the only problem - on a live server max number of connections will be reached immediately, and using persistent connection will make it even worse.
And yes, you should have titled your question other way, as people here never bother to read the question body but judge the question by its title only.
Setting persistent connection is a false solution. This feature has its own reasons to use which has noting to do with correcting initially wrong design.
The reason why you get your page loading slow is just creating a new database connection every time you run a query. As simple as that. So - create a PDO object only once and then pass it as a parameter (as most convenient and less hated by fanatics solution).
I typically create a database connection class. Usually it's a singleton. The PDO object is a protected property of the class. My model files will extend this class. Thus, I have a single PDO object which is secure because it can only be accessed by classes which extend the superclass.
Are you using prepared statements? This will enhance performance. It will also greatly reduce the risk of sqli attacks.
Here are some other things to consider when optimizing DB performance:
what storage engine are you using?
what are your mysql configuration settings?
are you using primary keys?
can you use a join instead of performing multiple queries?
can you cache queries?
do you have any particularly slow queries which could possibly be refactored?
HTH -- n
Hello all,
This query below contains the prepared statement that I would like to have mysqli processed
"SELECT password, salt FROM accounts WHERE username=?"
So far there seems to be no documentation on how fetch_array() works in OO-style with prepared statements. The closest thing I can find is http://php.net/manual/en/mysqli-result.fetch-array.php
Is there a particular "correct" way of doing it with mysqli prepared statements (the OO way)? thanks!
You won't get Objects directly out of the database with prepared statements.
Use fetch http://php.net/manual/en/mysqli-stmt.fetch.php to loop through the results, creating the required class instances and assigning them the data.
A model class will typically have a read method that does this. The method returns a instance, or an array of instances.
(Have a look at symfony models: http://www.symfony-project.org/book/1_0/08-inside-the-model-layer There are so-called peer models that provide static methods "to retrieve records from the tables. Their methods usually return an object or a collection of objects of the related object class".)
The Situation:
I am using a db class as a wrapper (dbwrapper) to open and close db connections via PHP PDO
I have 3 separate classes which extend this db wrapper
I instantiate 3 objects from said classes and in the course of their existence they each make db queries
MySQL used in this case.
When the methods of the 3 classes require db access they each create PDO objects internally, making use of the dbwrapper which they extended. Each object is storing its PDO object in a member/field for reference by itself.
The Question: My question is this... is each object creating a separate connection to the database, making 3 in total? Is each client of Apache creating only one connection to the database or is each object using the db in a php application creating a connection. (sounds inefficient!)
The Reason: I would like to understand how these connections are handled.
I am trying to decide if it would be better to have each class extend the dbwrapper or if it would be better to initialize the dbwrapper without making an automatic connection the db, handle that when its needed. Instead I would pass the dbwrapper to each objects constructor as they are initialized... letting them use that reference. If multiple db connections are happening then I think this would be the best way to minimize overhead while overcoming issues of object's scope and access.
Thanks in advance!
is each object creating a separate connection to the database, making 3 in total?
Maybe. I don't know, but here's how to find out. While your script is running, connect to MySQL via your client of choice (like the command line) and issue the command SHOW PROCESSLIST; You'll get a list of active connections.
You might need to insert a sleep in your script to keep it alive long enough for you to run the process list command when you've instantiated and are working on all three objects.
You'll see either one connection or three. Then you'll have your answer.
(The answer will vary depending on the underlying driver. Some drivers will reuse the connection if the DSN is identical.)
Instead I would pass the dbwrapper to each objects constructor as they are initialized... letting them use that reference
This is the common practice. Database handles are prime candidates for the Singleton pattern as well.