21

Is it possible to extend PHP PDO statement class to add custom methods to it? This would be different from extending the base PDO class. If so, how would one go about doing it since the statement class is only returned when running queries through the PDO class?

Levi Hackwith
  • 9,232
  • 18
  • 64
  • 115

4 Answers4

28

You can set the class with PDO::setAttribute():

PDO::ATTR_STATEMENT_CLASS: Set user-supplied statement class derived from PDOStatement. Cannot be used with persistent PDO instances. Requires array(string classname, array(mixed constructor_args)).

Example:

$pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, [Custom::class]);
Fabien Sa
  • 9,135
  • 4
  • 37
  • 44
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • 3
    Note that the default constructor takes no arguments (so no `array($pdo)` there). Furthermore, for usage in a namespace, you can use `Custom::class` instead of `'Custom'` which gives you the fully qualified class name respecting the current `use` imports. – bodo May 27 '16 at 17:25
4

This is answered by a user in the PHP Manual under PDO:

class Database extends PDO {
    function __construct($dsn, $username="", $password="", $driver_options=array()) {
        parent::__construct($dsn,$username,$password, $driver_options);
        $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('DBStatement', array($this)));
    }
}
class DBStatement extends PDOStatement {
    public $dbh;
    protected function __construct($dbh) {
        $this->dbh = $dbh;
    }
}

You can find his original answer by searching: 'smileaf' at this page: https://php.net/manual/en/book.pdo.php

iateadonut
  • 1,951
  • 21
  • 32
1

This is my code to save the result of a select query into a text file as insert statement. I first extend the PDOStatement class to add the custom method saveResultAsInsertStatement:

<?php
class MyPDOStatement extends PDOStatement {
    protected $pdo;

    protected function __construct($pdo) {
        $this->pdo = $pdo;
    }
    public function saveResultAsInsertStatement($filename) {
        $result = '';
        $columnData = $this->fetchAll(PDO::FETCH_ASSOC);
        if ($columnData != null) {
            $fieldCount = count($columnData[0]);
            $rowsCount = count($columnData);
            $columnsName = array_keys($columnData[0]);
            $result = "INSERT INTO %s ( \n";
            $result .= join(",\n", $columnsName);
            $result .= ") VALUES\n";
            $r = 0;
            foreach ($columnData as $row) {
                $result .= "(";
                $c = 0;
                foreach ($row as $key => $field) {
                    $result .= $this->pdo->quote($field);
                    $result .= ( ++$c < $fieldCount) ? ', ' : '';
                }
                $result .= ")";
                $result .= ( ++$r < $rowsCount) ? ',' : '';
                $result .= "\n";
            }
        }

        $f = fopen($filename, "w");
        fwrite($f, $result);
        fclose($f);
    }

}
?>

Then I extend the PDO class to set the attribute PDO::ATTR_STATEMENT_CLASS

<?php
class MyPDO extends PDO {
    public function __construct(... PDO constructor parameters here ... ) {
        parent::__construct( ... PDO construct parameters here ...);
        $this->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('MyPDOStatement', array($this)));
    }

}
?>

So then, I can write:

<?php
$conn = new MyPDO(... PDO constructor parameters here ...);

$sql = ... your select statement here...

$conn->query($sql)->saveResultAsInsertStatement(... name of the file here ...);


?>
max68
  • 31
  • 3
0

If you are using namespaces for your classes you need to add a backslash to your class string.

Without namespace:

$pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Custom', array($pdo)));

With namespace:

$pdo->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('Namespace\Custom', array($pdo)));
Devsper
  • 1
  • 1
  • 1