2

Because I find PDO executions extremely hard to remember and find myself looking back at previous projects or other websites just to remember how to select rows from a database, I decided that I would try and create my own functions that contain the PDO executions and just plug in the data I need. It seemed a lot simpler than it actually is though...

So far I have already created a connect function successfully, but now when it comes to create a select function I'm stumped for multiple reasons.
For starters there could be a variating amount of args that can be passed into the function and secondly I can't figure out what I should pass to the function and in which order.

So far the function looks like this. To keep me sane, I've added the "id" part to it so I can see what exactly I need to accomplish in the final outcome, and will be replaced by variables accordingly when I work out how to do it.

function sql_select($conn, **what to put here**) {
    try {
        $stmt = $conn->prepare('SELECT * FROM myTable WHERE id = :id');
        $stmt->execute(array('id' => $id));

        $result = $stmt->fetchAll();

        if ( count($result) ) {
            foreach($result as $row) {
                print_r($row);
            }
        } else {
            return "No rows returned.";
        }
    } catch(PDOException $e) {
        echo 'ERROR: ' . $e->getMessage();
    }
}

So far what I've established that the function will need to do is

  • Connect to the database (using another function to generate the $conn variable, already done)
  • Select the table
  • Specify the column
  • Supply the input to match
  • Allow for possible args such as ORDER by 'id' DESC

Lastly from this I would need to create a function to insert, update and delete rows from the database.

Or, is there a better way to do this rather than functions?

If anyone could help me accomplish my ambitions to simply simplify PDO executions it would be greatly appreciated. Thanks in advance!

3
  • 5
    If you're having trouble using PDO itself, what makes you think that wrapping PDO in other methods/functions would make it any easier? "I can't open this christmas present. I know! I'll wrap it in MORE stuff to make it easier to open!" Commented Dec 24, 2013 at 15:09
  • It's not that I have trouble using PDO, it's just hard to remember if you compare it to the [php.net/manual/en/book.mysql.php](depreciated original mysql api) which is where I've moved from over 6 months ago. All I'm trying to accomplish is essentially taking 10~ lines of code which into less so inserting or updating a row in a database is as quick and as easy to remember as it was with the old mysql api. Commented Dec 24, 2013 at 15:18
  • @SteppingHat - if you've got six months of development in PDO it's possibly a little late, but have you thought using mysqli instead? The functionality in procedural style is very similar to mysql, meaning there's less of a learning curve, but you can still write more secure code. Commented Dec 24, 2013 at 15:27

4 Answers 4

3

First of all, I have no idea where did you get 10 lines

$stmt = $conn->prepare('SELECT * FROM myTable WHERE id = ?');
$stmt->execute(array($id));
$result = $stmt->fetchAll();

is ALL the code you need, and it's actually three lines, which results with a regular PHP array that you can use wherever you wish. Without the need of any PDO code. Without the need of old mysql code.

Lastly from this I would need to create a function to insert, update and delete rows from the database.

DON'T ever do it.

Please read my explanations here and here based on perfect examples of what you'll end up if continue this way.

accomplish my ambitions to simply simplify PDO executions

That's indeed a great ambition. However, only few succeeded in a real real simplification, but most resulted with actually more complex code. For starter you can try code from the first linked answer. Having a class consists of several such functions will indeed improve your experience with PDO.

Sign up to request clarification or add additional context in comments.

13 Comments

Okay, I understand where to head now. Thanks :) But just small question. What about if something goes wrong in the execution? That's my reason for the try/catch block. For reference, this is where I learned everything I know about PDO: net.tutsplus.comtutorials/php/…
All these tutorials aren't worth a brass farthing. Only a few tutorial writers actually have an idea on the topic they write. If something goes wrong in the execution, you'll be notified as well, but much better and reliable way. Just try it and see. Without this try..catch you will have a more informative and helpful error message. Just let it out as any other PHP error. there is nothing special with PDO errors actually. And missing table error require no other treatment than missing file.
I disagree in regards to using PHP errors rather than exceptions. I always set PDO::ERRMODE_EXCEPTION and surround statements with try/catch blocks. Exception::getMessage will return excellent error info, and you won't have to implement a custom error handler to catch PHP errors. My two cents.
@JeremyKendall you are wrong. I always set PDO::ERRMODE_EXCEPTION too, but to surround statements with try/catch blocks is just a waste. Try to get rid of try and catch and see. In fact you'll get way better error handling.
We'll just have to agree to disagree then :-)
|
2

. . . and find myself looking back at previous projects or other websites just to remember how to select rows from a database . . .

FYI, we all do that.

You had a problem with the PDO API and now you have two problems. My best and strongest suggestion is this: If you want a simpler/different database API, do not roll your own. Search http://packagist.org for an ORM or a DBAL that looks good and use it instead of PDO.

Other people have already done this work for you. Use their work and focus instead on whatever awesome thing is unique to your app. Work smart, not hard and all that.

1 Comment

Yeah don't get me wrong that's extremely useful. But I just find that for something as common as reading a row in a database I shouldn't have to look back to do it every time. That's just my personal way of things though
1

Writting a wrapper, should start form connecting the DB, and all the possible method could be wrapped. Passing connection to the query method, doesn't look good.

A very rough example would be the code bellow, I strongly do not suggest this mixture, but it will give you the direction.

You connection should be made either from the constructor, or from another method called in the constructor, You can use something like this:

public function __construct($driver = NULL, $dbname = NULL, $host = NULL, $user = NULL, $pass = NULL, $port = NULL) {
        $driver     = $driver   ?: $this->_driver;
        $dbname     = $dbname   ?: $this->_dbname;
        $host       = $host     ?: $this->_host;
        $user       = $user     ?: $this->_user;
        $pass       = $pass     ?: $this->_password;
        $port       = $port     ?: $this->_port;
        try {
            $this->_dbh  = new PDO("$driver:host=$host;port=$port;dbname=$dbname", $user, $pass);
            $this->_dbh->exec("set names utf8");
        } catch(PDOException $e) {
            echo    $e->getMessage();  
        }
    }

So you can either pass connection credentials when you instantiate your wrapper or use default ones.

Now, you can make a method that just recieves the query. It's more OK to write the whole query, than just pass tables and columns. It will not make a whole ORM, but will just make the code harder to read.

In my first times dealing with PDO, I wanted everything to be dynamically, so what I achieved, later I realized is immature style of coding, but let's show it

public function query($sql, $unset = null) {
    $sth = $this->_dbh->prepare($sql);

    if($unset != null) {
        if(is_array($unset)) {
            foreach ($unset as $val) {
                unset($_REQUEST[$val]);
            }
        }
        unset($_REQUEST[$unset]);
    }

    foreach ($_REQUEST as $key => $value) { 
         if(is_int($value)) {
             $param = PDO::PARAM_INT;
         } elseif(is_bool($value)) {
             $param = PDO::PARAM_BOOL;
         } elseif(is_null($value)) {
             $param = PDO::PARAM_NULL;
         } elseif(is_string($value)) {
             $param = PDO::PARAM_STR;
         } else {
             $param = FALSE;   
         }
         $sth->bindValue(":$key", $value, $param);
    }

    $sth->execute();
    $result = $sth->fetchAll();

    return $result;

}

So what all of these spaghetti does?

First I though I would want all of my post values to be send as params, so if I have

input name='user'
input name='password'

I can do $res = $db->query("SELECT id FROM users WHERE username = :user AND password = :password");

And tada! I have fetched result of this query, $res is now an array containing the result.

Later I found, that if I have

input name='user'
input name='password'
input name='age'

In the same form, but the query remains with :user and :password and I submit the form, the called query will give mismatch in bound params, because the foreach against the $_REQUEST array will bind 3 params, but in the query I use 2.

So, I set the code in the beginning of the method, where I can provide what to exclude. Calling the method like $res = $db->query("SELECT id FROM users WHERE username = :user AND password = :password", 'age'); gave me the possibility to do it.

It works, but still is no good.

Better have a query() method that recieves 2 things:

  • The SQL string with the param names
  • The params as array.

So you can use the foreach() logic with bindValue, but not on the superglobal array, but on the passed on.

Then, you can wrap the fetch methods

public function fetch($res, $mode = null)

You should not directly return the fetch from the query, as it might be UPDATE, INSERT or DELETE.

Just pass the $res variable to the fetch() method, and a mode like PDO::FETCH_ASSOC. You can use default value where it would be fetch assoc, and if you pass something else, to use it.

Don't try to be so abstract, as I started to be. It will make you fill cracks lately.

1 Comment

Just as a quick note: The shorthand "?:" ternary operator is only available in PHP 5.3 and above.
1

Hum... IMHO I don't think you should try to wrap PDO in functions, because they're already "wrapped" in methods. In fact, going from OOP to procedural seems a step back (or at least a step in the wrong direction). PDO is a good library and has a lot of methods and features that you will surely lose if you wrap them in simple reusable functions.

One of those features is the BeginTransaction/Rollback (see more here)

Regardless, In a OOP point of view you can decorate the PDO object itself, adding some simple methods.

Here's an example based on your function

Note: THIS CODE IS UNTESTED!!!!

class MyPdo
{
    public function __construct($conn)
    {
        $this->conn = $conn;
    }
    

    public function pdo()
    {
        return $this->conn;
    }

    public function selectAllById($table, $id = null)
    {
        $query = 'SELECT * FROM :table';
        $params = array('table'=>$table);
        if (!is_null($id)) {
            $query .= ' WHERE id = :id';
            $params['id'] = $id;
        }
        $r = $this->conn->prepare($query)
                  ->execute($params)
                  ->fetchAll();
        //More stuff here to manipulate $r (results)
        return $r;
    }

    public function __call($name, $params)
    {
        call_user_func_array(array($this->conn, $name), $params);
    }
}

Note: THIS CODE IS UNTESTED!!!!


ORM

Another option is using an ORM, which would let you interact with your models/entities directly without bothering with creating/destroying connections, inserting/deleting, etc... Doctrine2 or Propel are good bets for PHP.

Howeveran ORM is a lot more complex than using PDO directly.

1 Comment

+1 for creating a class that uses PDO to create a clean API for a very specific purpose. I do this quite a lot. Here's an example User data access object I'm using in a current project.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.