2

I want to start using PDO (switching from MySQL extension) and I would like to add some methods but to still have the entire PDO functionality. I would like to implement a function like this:

$db->getAll("SELECT * FROM table WHERE field1=:foo AND field2=:baz", array('foo'=>$foo, 'baz'=>$baz));

I think the best way is to extend the PDO class but in this case I would not have the instance of the class to be able to use it inside the class. Any idea?

denied
  • 133
  • 2
  • 9

3 Answers3

4

I would advise against extending PDO, but rather creating a library/wrapper around it which other ORM's do.

I will construct your example code into a simple class for explanation.

class MyDB
{

    private $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function getAll($query, array $params)
    {
        $statement = $this->pdo->prepare($query);
        $statement->execute($params);
        return $statement->fetchAll();
    }

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

    /**
     * This is called if the method cannot be found.
     * Pass it to PDO to handle.
     *
     * @param $name
     * @param $arguments
     */
    public function __call($name, $arguments)
    {
        return call_user_func(array($this->pdo, $name), $arguments)
    }

}

If you really want to access PDO directly then I've included a magic method but I don't recommend you take that route. See http://www.php.net/manual/en/language.oop5.magic.php

Doing this sort of stuff is fun for learning, but if you want a serious ORM then take a look at this SO question Good PHP ORM Library? and also research yourself.

Community
  • 1
  • 1
SamV
  • 7,548
  • 4
  • 39
  • 50
  • Or one may choose to use one of the existing libraries already doing this :) – KingCrunch Dec 13 '13 at 13:08
  • Yeah or that, which I would prefer! – SamV Dec 13 '13 at 13:08
  • Great example: when possible, choose composition over inheritance – douwe Dec 13 '13 at 13:13
  • Why did you edit your answer? What's wrong with creating PDO instance inside? – Your Common Sense Dec 13 '13 at 13:14
  • So you can test the class by mocking the PDO. @YourCommonSense – SamV Dec 13 '13 at 13:22
  • Thank you @FruityP but only the getAll method works. I also want to use all the PDO functionality. I want to be able to do something like this: `$db = new Db($pdoObject); $users = $db->getAll("SELECT * FROM users", array('email'=>'email@gmail.com'));` AND to also have the functionality of PDO on the same object, like this: `$statement = $db->prepare("SELECT * FROM users"); $statement->execute(array('email'=>'email@gmail.com'));` – denied Dec 13 '13 at 14:08
  • 1
    See edited code @denied, you can just add a getter method so `$pdo = $db->getPdo(); $pdo->prepare()` etc... – SamV Dec 13 '13 at 14:14
  • @FruityP I often write complex queries with joins and subqueries. Do you still recommend using an ORM for this kind of queries? Which one would you recommend? – denied Dec 14 '13 at 18:35
  • @denied This is getting off the topic of the question, a simple google search on the matter will yield a plethora of information and a few SO questions. I've already linked one in the answer. – SamV Dec 14 '13 at 18:38
  • "I would advise against extending PDO" why? – Yousha Aleayoub Jun 11 '20 at 11:52
0

Just before you get deep in your project here is an advice for you. Do it with ORM library.

For example I am doing the same thing you need with ORM library (in this case called db.php) like this:

$database->path->to->table->handler->load (\db\by('field1',$value1)->by('field2',$field2));

The complicated thing with ORMs are that they need class definitions to work with tables and many PHP developers are afraid of class definitions for their data objects. For above example to work you should have needed a class definition something like this:

namespace \path\to;
class table
{
    public $field1;
    public $field2;
}

And database initialization in case of db.php ORM library like this:

$database = new \db\database ('mysql:host=127.0.0.1', 'test_db', 'root', '1234');

And class attaching to database object to handle like this:

$database->add ('\path\to\table');

Additionally many ORMs have a magic method allowing you to automatically create or generate tables according your class definitions, for example db.php (http://dbphp.net) method:

$database->update();

Will create path_to_table table in your actual mysql database with 2 fields field1 and field2.

I am not sure why people should be afraid ORMs in PHP development they make life easier for everybody and give abilities not to get confused in your own code when you are working on large scale projects.

I believe sometimes this answer will save at least 1 human from future sufferings.

: D

BIOHAZARD
  • 1,937
  • 20
  • 23
-6

a singleton example:

class DB
{
    protected static $instance = null;

    final private function __construct() {}
    final private function __clone() {}

    public static function instance()
    {
        if (self::$instance === null)
        {
            $dsn = 'mysql:host='.DB_HOST.';dbname='.DB_NAME;
            self::$instance = new PDO($dsn, DB_USER, DB_PASS);
            self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        return self::$instance;
    }
    public static function __callStatic($method, $args) {
        return call_user_func_array(array(self::instance(), $method), $args);
    }

    public static function getAll($sql, $data = NULL, $mode = PDO::FETCH_ASSOC)
    {
        $stmt = self::instance()->prepare($sql);
        $stmt->execute($data);
        return $stmt->fetchAll($mode);
    }
}

$sql  = "SELECT * FROM table WHERE field1=:foo AND field2=:baz";
$data = DB::getAll($sql, array('foo'=>$foo, 'baz'=>$baz));
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • 1
    Singleton is an antipattern. Just saying ... The argument "but in some cases .." isn't valid, when it's about database connections, from which you may or may not need more than once ;) – KingCrunch Dec 13 '13 at 13:08
  • It makes me wonder, why Laravel is using a singleton all the way with database interaction. May be it is not *that* anti-pattern as some think. – Your Common Sense Dec 13 '13 at 13:10
  • 2
    "Sombody uses it, it must be best-practice"? Are you kidding? – KingCrunch Dec 13 '13 at 13:11
  • No kidding. Laravel considered the best PHP framework to-day. I didn't say "best" though. Some people indeed think in binaries: ether practice "best" or "worst", no shades. – Your Common Sense Dec 13 '13 at 13:12
  • 1
    "The best framework" is a quite brave statement. Who said this? Whats about the other frameworks? Symfony2? ZF2? Aura? ... But #topic: Tell me, how can I access a second database? How can I test my component, that access the DB? How can I get rid of the instance, to release the resources? // Update: I had a look and what Laravel uses is an imitation of the Registry-pattern. – KingCrunch Dec 13 '13 at 13:16
  • Well, to access another database you can use another singleton class. both extending base DB class. I see no problem with adding kill() method to the class. I am not a testing pro, but I am sure there are methods to deal with singletons. – Your Common Sense Dec 13 '13 at 13:25