SlideShare a Scribd company logo
PHP 101: PDO
                            or:
How I Learned to Stop Worrying and Love
        Data Access Abstraction




         Jeremy Kendall | Memphis PHP | July 26, 2012
What is PDO?
• PDO == PHP Data Objects
• Lightweight, consistent interface for
  accessing databases in PHP
• Provides data access abstraction, not
  database abstraction
• Ships with PHP 5.1
• PECL extension for 5.0
Drivers include . . .

• MySQL
• PostgreSQL
• SQL Server
• SQLite
• and more . . .
Which drivers do I have?

•   var_dump(PDO::getAvailableDrivers());

•   If you don’t see what you need, check php.ini
Working with databases
• Solved problem, you don’t have to write
  anything yourself
• PHP and MySQL have an especially rich
  history
• CRUD is the easy part
• Creating clean, maintainable code is the
  challenge
Let’s look at some
typical procedural code
What we’re building
mysql
<?php
$conn = mysql_connect('localhost', 'testuser', 'testpass')
    or die('Could not connect: ' . mysql_error());

mysql_select_db('bookshelf')
    or die('Could not select bookshelf');

$result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn)
    or die('Invalid query: ' . mysql_error());
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysql_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysql_close($conn);
mysql
<?php
$conn = mysql_connect('localhost', 'testuser', 'testpass')
    or die('Could not connect: ' . mysql_error());

mysql_select_db('bookshelf')
    or die('Could not select bookshelf');

$result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn)
    or die('Invalid query: ' . mysql_error());
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysql_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysql_close($conn);
mysql
<?php
$conn = mysql_connect('localhost', 'testuser', 'testpass')
    or die('Could not connect: ' . mysql_error());

mysql_select_db('bookshelf')
    or die('Could not select bookshelf');

$result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn)
    or die('Invalid query: ' . mysql_error());
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysql_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysql_close($conn);
mysql
<?php
$conn = mysql_connect('localhost', 'testuser', 'testpass')
    or die('Could not connect: ' . mysql_error());

mysql_select_db('bookshelf')
    or die('Could not select bookshelf');

$result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn)
    or die('Invalid query: ' . mysql_error());
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysql_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysql_close($conn);
mysql
<?php
$conn = mysql_connect('localhost', 'testuser', 'testpass')
    or die('Could not connect: ' . mysql_error());

mysql_select_db('bookshelf')
    or die('Could not select bookshelf');

$result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn)
    or die('Invalid query: ' . mysql_error());
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysql_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysql_close($conn);
mysql
<?php
$conn = mysql_connect('localhost', 'testuser', 'testpass')
    or die('Could not connect: ' . mysql_error());

mysql_select_db('bookshelf')
    or die('Could not select bookshelf');

$result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn)
    or die('Invalid query: ' . mysql_error());
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysql_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysql_close($conn);
Oops!
Should have used mysqli!
mysqli
<?php
$conn = mysqli_connect('localhost', 'testuser', 'testpass', 'bookshelf')
    or die('Could not connect: ' . mysqli_connect_error());

$result = mysqli_query($conn, 'SELECT * FROM bookshelf ORDER BY title')
    or die('Invalid query: ' . mysqli_error($conn));
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = mysqli_fetch_assoc($result)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
mysqli_close($conn);
Refactoring problems
// You can't simply find and replace
// because of differences in the interfaces

// mysql_query wants query first and connection second
$result = mysql_query($query, $conn);

// mysqli_query is exactly opposite
$result = mysqli_query($conn, $query);
Refactoring problems
// You can't simply find and replace
// because of differences in the interfaces

// mysql_query wants query first and connection second
$result = mysql_query($query, $conn);

// mysqli_query is exactly opposite
$result = mysqli_query($conn, $query);
Refactoring problems
// You can't simply find and replace
// because of differences in the interfaces

// mysql_query wants query first and connection second
$result = mysql_query($query, $conn);

// mysqli_query is exactly opposite
$result = mysqli_query($conn, $query);
Changing DB vendors?
     Have fun with that.
sqlsrv
<?php
$connectionInfo = array(
    'Database' => 'bookshelf',
    'UID' => 'testuser',
    'PWD' => 'testpass'
);
$conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo);
$stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title');
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
sqlsrv_close($conn);
sqlsrv
<?php
$connectionInfo = array(
    'Database' => 'bookshelf',
    'UID' => 'testuser',
    'PWD' => 'testpass'
);
$conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo);
$stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title');
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
sqlsrv_close($conn);
sqlsrv
<?php
$connectionInfo = array(
    'Database' => 'bookshelf',
    'UID' => 'testuser',
    'PWD' => 'testpass'
);
$conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo);
$stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title');
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
sqlsrv_close($conn);
sqlsrv
<?php
$connectionInfo = array(
    'Database' => 'bookshelf',
    'UID' => 'testuser',
    'PWD' => 'testpass'
);
$conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo);
$stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title');
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
sqlsrv_close($conn);
sqlsrv
<?php
$connectionInfo = array(
    'Database' => 'bookshelf',
    'UID' => 'testuser',
    'PWD' => 'testpass'
);
$conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo);
$stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title');
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php
sqlsrv_close($conn);
Php 101: PDO
But what can you do
     about it?
You could roll your own
<?php

class MyDb
{
    public function __construct($host, $username, $password, $dbname)
    {

    }

    public function query($sql, array $bind)
    {

    }

    // . . .
}
Or don’t and use PDO
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
<?php

$dsn = 'mysql:host=localhost;dbname=bookshelf';
$username = 'testuser';
$password = 'testpass';

$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);

try {
    $dbh = new PDO($dsn, $username, $password, $options);
} catch (PDOException $e) {
    echo 'Error!: ' . $e->getMessage();
    die();
}

// $result is an array, so we can use array functions rather than db vendor functions
$result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll();
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($result as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
But I’m going to use
 SQLite in DEV . . .
No problem!
Change the dsn, username, and password. Done.
   $dsn = 'mysql:host=localhost;dbname=bookshelf';
   $username = 'testuser';
   $password = 'testpass';


                   becomes
   $dsn = 'sqlite:' . realpath('./data/db/bookshelf.db');
   $username = null;
   $password = null;
Connecting

• DSN required, username & pass optional
• A connection error always throws an
    Exception, so use try/catch
•   Closing a connection is as simple as $dbh = null
Errors and Exceptions
• Three error modes
  •   PDO::ERRMODE_SILENT

  •   PDO::ERRMODE_WARNING

  •   PDO::ERRMODE_EXCEPTION


• Always use exceptions
• No, really, use exceptions
Insert, Update, Delete
• PDO::exec()
• Returns # rows affected
• Won’t return results of SELECT
• Won’t escape data (use PDO::quote())
Delete example
/* quote string */
$title = $dbh->quote('Refactoring');

/* Delete a book */
$count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title");

/* Return number of rows that were deleted */
print("Deleted $count rows.n");
Delete example
/* quote string */
$title = $dbh->quote('Refactoring');

/* Delete a book */
$count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title");

/* Return number of rows that were deleted */
print("Deleted $count rows.n");
Delete example
/* quote string */
$title = $dbh->quote('Refactoring');

/* Delete a book */
$count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title");

/* Return number of rows that were deleted */
print("Deleted $count rows.n");
Delete example
/* quote string */
$title = $dbh->quote('Refactoring');

/* Delete a book */
$count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title");

/* Return number of rows that were deleted */
print("Deleted $count rows.n");
In almost all cases, favor
  prepared statements
    over PDO::exec()
Prepared statements
• To know them is to love them
• No more SQL injection
• Can execute same statement multiple times
  with different values
• Efficient (in most cases)
• Positional, named
• The one feature PDO emulates
Prepared statements
                    Using named parameters:
$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->bindParam('title', $title);
$statement->bindParam('author', $author);

$books = array(
    "Clean Code" => "Robert C. Martin",
    "Refactoring" => "Martin Fowler",
    "Test-Driven Development" => "Kent Beck",
    "The Agile Samurai" => "Jonathan Rasmusson",
    "Working Effectively with Legacy Code" => "Michael Feathers"
);

foreach ($books as $title => $author) {
    $setup->execute();
}
Prepared statements
                    Using named parameters:
$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->bindParam('title', $title);
$statement->bindParam('author', $author);

$books = array(
    "Clean Code" => "Robert C. Martin",
    "Refactoring" => "Martin Fowler",
    "Test-Driven Development" => "Kent Beck",
    "The Agile Samurai" => "Jonathan Rasmusson",
    "Working Effectively with Legacy Code" => "Michael Feathers"
);

foreach ($books as $title => $author) {
    $setup->execute();
}
Prepared statements
                    Using named parameters:
$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->bindParam('title', $title);
$statement->bindParam('author', $author);

$books = array(
    "Clean Code" => "Robert C. Martin",
    "Refactoring" => "Martin Fowler",
    "Test-Driven Development" => "Kent Beck",
    "The Agile Samurai" => "Jonathan Rasmusson",
    "Working Effectively with Legacy Code" => "Michael Feathers"
);

foreach ($books as $title => $author) {
    $setup->execute();
}
Prepared statements
                    Using named parameters:
$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->bindParam('title', $title);
$statement->bindParam('author', $author);

$books = array(
    "Clean Code" => "Robert C. Martin",
    "Refactoring" => "Martin Fowler",
    "Test-Driven Development" => "Kent Beck",
    "The Agile Samurai" => "Jonathan Rasmusson",
    "Working Effectively with Legacy Code" => "Michael Feathers"
);

foreach ($books as $title => $author) {
    $setup->execute();
}
Prepared statements
                  Using positional parameters:

$sql = "INSERT INTO bookshelf (title, author) VALUES (?, ?)";
$statement = $dbh->prepare($sql);
$statement->bindParam(1, $title);
$statement->bindParam(2, $author);

$books = array(
    "Clean Code" => "Robert C. Martin",
    "Refactoring" => "Martin Fowler",
    "Test-Driven Development" => "Kent Beck",
    "The Agile Samurai" => "Jonathan Rasmusson",
    "Working Effectively with Legacy Code" => "Michael Feathers"
);

foreach ($books as $title => $author) {
    $setup->execute();
}
Prepared statements
          Array of named params to PDO::execute

$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->execute(array('title' => $title, 'author' => $author));
Prepared statements
          Array of named params to PDO::execute

$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->execute(array('title' => $title, 'author' => $author));
Prepared statements
          Array of named params to PDO::execute

$sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)";
$statement = $dbh->prepare($sql);
$statement->execute(array('title' => $title, 'author' => $author));
Select

• Gets data from the database
• Results returned as PDOStatement
• How data is fetched from statement
  depends on fetch mode
• Grab all results at once with fetchAll()
Fetch modes
• Can be set in constructor or later with
  PDO::setAttribute() or
  PDOStatement::setFetchMode()
• PDO::FETCH_ASSOC
• PDO::FETCH_BOTH (default)
• PDO::FETCH_NUM
• PDO::FETCH_OBJ
• to name a few . . .
Fetching
// Gets all books in database
$stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title");

// Returns array of all results
$books = $stmt->fetchAll();

// Returns next row in manner determined by fetch mode
$row = $stmt->fetch();

// Can choose fetch mode at time of fetch
$row = $stmt->fetch(PDO::FETCH_OBJ);
Fetching
// Gets all books in database
$stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title");

// Returns array of all results
$books = $stmt->fetchAll();

// Returns next row in manner determined by fetch mode
$row = $stmt->fetch();

// Can choose fetch mode at time of fetch
$row = $stmt->fetch(PDO::FETCH_OBJ);
Fetching
// Gets all books in database
$stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title");

// Returns array of all results
$books = $stmt->fetchAll();

// Returns next row in manner determined by fetch mode
$row = $stmt->fetch();

// Can choose fetch mode at time of fetch
$row = $stmt->fetch(PDO::FETCH_OBJ);
Fetching
// Gets all books in database
$stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title");

// Returns array of all results
$books = $stmt->fetchAll();

// Returns next row in manner determined by fetch mode
$row = $stmt->fetch();

// Can choose fetch mode at time of fetch
$row = $stmt->fetch(PDO::FETCH_OBJ);
Fetching
// Gets all books in database
$stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title");

// Returns array of all results
$books = $stmt->fetchAll();

// Returns next row in manner determined by fetch mode
$row = $stmt->fetch();

// Can choose fetch mode at time of fetch
$row = $stmt->fetch(PDO::FETCH_OBJ);
Fetching
       PDOStatement implements Traversable,
              which allows you to:
$stmt = $dbh->query('SELECT * FROM bookshelf ORDER BY title');

?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($stmt as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
Fetching
       PDOStatement implements Traversable,
              which allows you to:
$stmt = $dbh->query('SELECT * FROM bookshelf ORDER BY title');

?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    foreach ($stmt as $row) {
         echo "<tr>";
         echo "<td>{$row['title']}</td><td>{$row['author']}</td>";
         echo "</tr>";
    }
    ?>
</table>
Fetching
                   PDO::FETCH_BOUND is slick

$stmt = $dbh->query('SELECT id, title, author FROM bookshelf ORDER BY title');
$stmt->bindColumn('title', $title);
$stmt->bindColumn('author', $author);
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($stmt->fetch(PDO::FETCH_BOUND)) {
         echo "<tr>";
         echo "<td>$title</td><td>$author</td>";
         echo "</tr>";
    }
    ?>
</table>
Fetching
                   PDO::FETCH_BOUND is slick

$stmt = $dbh->query('SELECT id, title, author FROM bookshelf ORDER BY title');
$stmt->bindColumn('title', $title);
$stmt->bindColumn('author', $author);
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($stmt->fetch(PDO::FETCH_BOUND)) {
         echo "<tr>";
         echo "<td>$title</td><td>$author</td>";
         echo "</tr>";
    }
    ?>
</table>
Fetching
                   PDO::FETCH_BOUND is slick

$stmt = $dbh->query('SELECT id, title, author FROM bookshelf ORDER BY title');
$stmt->bindColumn('title', $title);
$stmt->bindColumn('author', $author);
?>
<table>
    <tr>
         <th>Title</th><th>Author</th>
    </tr>
    <?php
    while ($stmt->fetch(PDO::FETCH_BOUND)) {
         echo "<tr>";
         echo "<td>$title</td><td>$author</td>";
         echo "</tr>";
    }
    ?>
</table>
But wait, there’s more!
PDO::lastInsertId()

• Returns the ID of the last inserted row
• Or the last value from a sequence object
• Be careful, some databases don’t support
  this and may exhibit unexpected behavior
Transactions

• PDO::beginTransaction()
• PDO::commit()
• PDO::rollback()
• Check your DB documentation for support
Benefits

• Maintainability
• Portability (with a few vendor specific
  caveats)
• Safety (prepared statements)
• Object oriented
Drawbacks
• Not all vendor specific features supported
• Interface is almost the same for all
  databases
• Slower in some cases
• Mediocre Oracle support (who uses
  Oracle?)
Portable, mostly
• Every DB has its own oddities and gotchas
• PDO offers data access abstraction
• You’ll likely still have to tweak if you’re doing
  anything other than very simple CRUD
• Still better than mysql_*, mysqli_*, sqlsrv_*
• Choose a DBAL like Doctrine if you need
  more
Credits
•   PHP Data Objects by Wez Furlong: http://
    www.slideshare.net/wezfurlong/php-data-objects

•   Nettuts+: http://net.tutsplus.com/tutorials/php/why-you-
    should-be-using-phps-pdo-for-database-access/

•   Introduction to PDO: http://www.dreamincode.net/
    forums/topic/214733-introduction-to-pdo/

•   php.net: http://us.php.net/manual/en/class.pdo.php
Questions?
Thanks!

• @JeremyKendall
• jeremy@jeremykendall.net
• http://about.me/jeremykendall

More Related Content

PDF
Certificado 1er Curso de Cementacion
PPT
PHP - PDO Objects
PDF
PHP Data Objects
PDF
PHP WTF
PDF
PHP 7 performances from PHP 5
PDF
PHP, Under The Hood - DPC
PDF
PHP 7 new engine
PPTX
Certificado 1er Curso de Cementacion
PHP - PDO Objects
PHP Data Objects
PHP WTF
PHP 7 performances from PHP 5
PHP, Under The Hood - DPC
PHP 7 new engine

Viewers also liked (9)

PPTX
Php internal architecture
PDF
Being functional in PHP (PHPDay Italy 2016)
PPTX
Internet of Things With PHP
PPTX
PHP Optimization
PPTX
Laravel Beginners Tutorial 1
PPT
How PHP Works ?
PDF
[Community Open Camp] 給 PHP 開發者的 VS Code 指南
PDF
LaravelConf Taiwan 2017 開幕
PDF
Route 路由控制
Php internal architecture
Being functional in PHP (PHPDay Italy 2016)
Internet of Things With PHP
PHP Optimization
Laravel Beginners Tutorial 1
How PHP Works ?
[Community Open Camp] 給 PHP 開發者的 VS Code 指南
LaravelConf Taiwan 2017 開幕
Route 路由控制
Ad

Similar to Php 101: PDO (20)

ODP
Php 102: Out with the Bad, In with the Good
PDF
PHP and Mysql
PDF
Hacking Your Way To Better Security
PPTX
Hacking Your Way to Better Security - PHP South Africa 2016
PPTX
Hacking Your Way To Better Security - Dutch PHP Conference 2016
PPTX
Hacking Your Way To Better Security - DrupalCon Baltimore 2017
PPTX
Hacking Your Way to Better Security - ZendCon 2016
PPT
Php Mysql
PDF
Mysql & Php
PPTX
lecture 7 - Introduction to MySQL with PHP.pptx
PDF
Hacking Your Way To Better Security - php[tek] 2016
PPTX
Unit 4- Working with SQL.pptx
PPT
PHP - Getting good with MySQL part II
PPTX
FYBSC IT Web Programming Unit V Advanced PHP and MySQL
PPTX
Database Connectivity MYSQL by Dr.C.R.Dhivyaa Kongu Engineering College
PPTX
UNIT V (5).pptx
PPTX
PHP and MySQL.pptx
PDF
PHP with MySQL
PPTX
CHAPTER six DataBase Driven Websites.pptx
PPTX
Php mysq
Php 102: Out with the Bad, In with the Good
PHP and Mysql
Hacking Your Way To Better Security
Hacking Your Way to Better Security - PHP South Africa 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - DrupalCon Baltimore 2017
Hacking Your Way to Better Security - ZendCon 2016
Php Mysql
Mysql & Php
lecture 7 - Introduction to MySQL with PHP.pptx
Hacking Your Way To Better Security - php[tek] 2016
Unit 4- Working with SQL.pptx
PHP - Getting good with MySQL part II
FYBSC IT Web Programming Unit V Advanced PHP and MySQL
Database Connectivity MYSQL by Dr.C.R.Dhivyaa Kongu Engineering College
UNIT V (5).pptx
PHP and MySQL.pptx
PHP with MySQL
CHAPTER six DataBase Driven Websites.pptx
Php mysq
Ad

More from Jeremy Kendall (15)

PDF
Leveraging the Power of Graph Databases in PHP
PDF
Leveraging the Power of Graph Databases in PHP
PDF
5 Ways to Awesome-ize Your (PHP) Code
PDF
Game Changing Dependency Management
PDF
Keeping it small - Getting to know the Slim PHP micro framework
PDF
Keeping it Small: Getting to know the Slim Micro Framework
KEY
Keeping it small: Getting to know the Slim micro framework
ODP
PHP 102: Out with the Bad, In with the Good
ODP
Intro to #memtech PHP 2011-12-05
ODP
TDD in PHP - Memphis PHP 2011-08-25
ODP
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
PDF
Zero to ZF in 10 Minutes
ODP
Tdd in php a brief example
ODP
A Brief Introduction to Zend_Form
ODP
Zero to Zend Framework in 10 minutes
Leveraging the Power of Graph Databases in PHP
Leveraging the Power of Graph Databases in PHP
5 Ways to Awesome-ize Your (PHP) Code
Game Changing Dependency Management
Keeping it small - Getting to know the Slim PHP micro framework
Keeping it Small: Getting to know the Slim Micro Framework
Keeping it small: Getting to know the Slim micro framework
PHP 102: Out with the Bad, In with the Good
Intro to #memtech PHP 2011-12-05
TDD in PHP - Memphis PHP 2011-08-25
Zend_Form to the Rescue - A Brief Introduction to Zend_Form
Zero to ZF in 10 Minutes
Tdd in php a brief example
A Brief Introduction to Zend_Form
Zero to Zend Framework in 10 minutes

Recently uploaded (20)

PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Mushroom cultivation and it's methods.pdf
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Getting Started with Data Integration: FME Form 101
PPTX
A Presentation on Artificial Intelligence
PDF
A comparative study of natural language inference in Swahili using monolingua...
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
gpt5_lecture_notes_comprehensive_20250812015547.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
PDF
Heart disease approach using modified random forest and particle swarm optimi...
PPTX
1. Introduction to Computer Programming.pptx
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PPTX
TLE Review Electricity (Electricity).pptx
PPTX
cloud_computing_Infrastucture_as_cloud_p
PDF
Machine learning based COVID-19 study performance prediction
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
Advanced methodologies resolving dimensionality complications for autism neur...
Spectral efficient network and resource selection model in 5G networks
Mushroom cultivation and it's methods.pdf
Network Security Unit 5.pdf for BCA BBA.
Getting Started with Data Integration: FME Form 101
A Presentation on Artificial Intelligence
A comparative study of natural language inference in Swahili using monolingua...
Encapsulation_ Review paper, used for researhc scholars
Diabetes mellitus diagnosis method based random forest with bat algorithm
gpt5_lecture_notes_comprehensive_20250812015547.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
TechTalks-8-2019-Service-Management-ITIL-Refresh-ITIL-4-Framework-Supports-Ou...
Heart disease approach using modified random forest and particle swarm optimi...
1. Introduction to Computer Programming.pptx
MIND Revenue Release Quarter 2 2025 Press Release
TLE Review Electricity (Electricity).pptx
cloud_computing_Infrastucture_as_cloud_p
Machine learning based COVID-19 study performance prediction
Mobile App Security Testing_ A Comprehensive Guide.pdf

Php 101: PDO

  • 1. PHP 101: PDO or: How I Learned to Stop Worrying and Love Data Access Abstraction Jeremy Kendall | Memphis PHP | July 26, 2012
  • 2. What is PDO? • PDO == PHP Data Objects • Lightweight, consistent interface for accessing databases in PHP • Provides data access abstraction, not database abstraction • Ships with PHP 5.1 • PECL extension for 5.0
  • 3. Drivers include . . . • MySQL • PostgreSQL • SQL Server • SQLite • and more . . .
  • 4. Which drivers do I have? • var_dump(PDO::getAvailableDrivers()); • If you don’t see what you need, check php.ini
  • 5. Working with databases • Solved problem, you don’t have to write anything yourself • PHP and MySQL have an especially rich history • CRUD is the easy part • Creating clean, maintainable code is the challenge
  • 6. Let’s look at some typical procedural code
  • 8. mysql <?php $conn = mysql_connect('localhost', 'testuser', 'testpass') or die('Could not connect: ' . mysql_error()); mysql_select_db('bookshelf') or die('Could not select bookshelf'); $result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn) or die('Invalid query: ' . mysql_error()); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysql_close($conn);
  • 9. mysql <?php $conn = mysql_connect('localhost', 'testuser', 'testpass') or die('Could not connect: ' . mysql_error()); mysql_select_db('bookshelf') or die('Could not select bookshelf'); $result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn) or die('Invalid query: ' . mysql_error()); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysql_close($conn);
  • 10. mysql <?php $conn = mysql_connect('localhost', 'testuser', 'testpass') or die('Could not connect: ' . mysql_error()); mysql_select_db('bookshelf') or die('Could not select bookshelf'); $result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn) or die('Invalid query: ' . mysql_error()); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysql_close($conn);
  • 11. mysql <?php $conn = mysql_connect('localhost', 'testuser', 'testpass') or die('Could not connect: ' . mysql_error()); mysql_select_db('bookshelf') or die('Could not select bookshelf'); $result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn) or die('Invalid query: ' . mysql_error()); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysql_close($conn);
  • 12. mysql <?php $conn = mysql_connect('localhost', 'testuser', 'testpass') or die('Could not connect: ' . mysql_error()); mysql_select_db('bookshelf') or die('Could not select bookshelf'); $result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn) or die('Invalid query: ' . mysql_error()); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysql_close($conn);
  • 13. mysql <?php $conn = mysql_connect('localhost', 'testuser', 'testpass') or die('Could not connect: ' . mysql_error()); mysql_select_db('bookshelf') or die('Could not select bookshelf'); $result = mysql_query('SELECT * FROM bookshelf ORDER BY title', $conn) or die('Invalid query: ' . mysql_error()); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysql_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysql_close($conn);
  • 15. mysqli <?php $conn = mysqli_connect('localhost', 'testuser', 'testpass', 'bookshelf') or die('Could not connect: ' . mysqli_connect_error()); $result = mysqli_query($conn, 'SELECT * FROM bookshelf ORDER BY title') or die('Invalid query: ' . mysqli_error($conn)); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = mysqli_fetch_assoc($result)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php mysqli_close($conn);
  • 16. Refactoring problems // You can't simply find and replace // because of differences in the interfaces // mysql_query wants query first and connection second $result = mysql_query($query, $conn); // mysqli_query is exactly opposite $result = mysqli_query($conn, $query);
  • 17. Refactoring problems // You can't simply find and replace // because of differences in the interfaces // mysql_query wants query first and connection second $result = mysql_query($query, $conn); // mysqli_query is exactly opposite $result = mysqli_query($conn, $query);
  • 18. Refactoring problems // You can't simply find and replace // because of differences in the interfaces // mysql_query wants query first and connection second $result = mysql_query($query, $conn); // mysqli_query is exactly opposite $result = mysqli_query($conn, $query);
  • 19. Changing DB vendors? Have fun with that.
  • 20. sqlsrv <?php $connectionInfo = array( 'Database' => 'bookshelf', 'UID' => 'testuser', 'PWD' => 'testpass' ); $conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo); $stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php sqlsrv_close($conn);
  • 21. sqlsrv <?php $connectionInfo = array( 'Database' => 'bookshelf', 'UID' => 'testuser', 'PWD' => 'testpass' ); $conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo); $stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php sqlsrv_close($conn);
  • 22. sqlsrv <?php $connectionInfo = array( 'Database' => 'bookshelf', 'UID' => 'testuser', 'PWD' => 'testpass' ); $conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo); $stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php sqlsrv_close($conn);
  • 23. sqlsrv <?php $connectionInfo = array( 'Database' => 'bookshelf', 'UID' => 'testuser', 'PWD' => 'testpass' ); $conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo); $stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php sqlsrv_close($conn);
  • 24. sqlsrv <?php $connectionInfo = array( 'Database' => 'bookshelf', 'UID' => 'testuser', 'PWD' => 'testpass' ); $conn = sqlsrv_connect('serverNameinstanceName', $connectionInfo); $stmt = sqlsrv_query($conn, 'SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table> <?php sqlsrv_close($conn);
  • 26. But what can you do about it?
  • 27. You could roll your own <?php class MyDb { public function __construct($host, $username, $password, $dbname) { } public function query($sql, array $bind) { } // . . . }
  • 28. Or don’t and use PDO
  • 29. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 30. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 31. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 32. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 33. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 34. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 35. <?php $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; $options = array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC ); try { $dbh = new PDO($dsn, $username, $password, $options); } catch (PDOException $e) { echo 'Error!: ' . $e->getMessage(); die(); } // $result is an array, so we can use array functions rather than db vendor functions $result = $dbh->query('SELECT * FROM bookshelf ORDER BY title')->fetchAll(); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($result as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 36. But I’m going to use SQLite in DEV . . .
  • 37. No problem! Change the dsn, username, and password. Done. $dsn = 'mysql:host=localhost;dbname=bookshelf'; $username = 'testuser'; $password = 'testpass'; becomes $dsn = 'sqlite:' . realpath('./data/db/bookshelf.db'); $username = null; $password = null;
  • 38. Connecting • DSN required, username & pass optional • A connection error always throws an Exception, so use try/catch • Closing a connection is as simple as $dbh = null
  • 39. Errors and Exceptions • Three error modes • PDO::ERRMODE_SILENT • PDO::ERRMODE_WARNING • PDO::ERRMODE_EXCEPTION • Always use exceptions • No, really, use exceptions
  • 40. Insert, Update, Delete • PDO::exec() • Returns # rows affected • Won’t return results of SELECT • Won’t escape data (use PDO::quote())
  • 41. Delete example /* quote string */ $title = $dbh->quote('Refactoring'); /* Delete a book */ $count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title"); /* Return number of rows that were deleted */ print("Deleted $count rows.n");
  • 42. Delete example /* quote string */ $title = $dbh->quote('Refactoring'); /* Delete a book */ $count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title"); /* Return number of rows that were deleted */ print("Deleted $count rows.n");
  • 43. Delete example /* quote string */ $title = $dbh->quote('Refactoring'); /* Delete a book */ $count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title"); /* Return number of rows that were deleted */ print("Deleted $count rows.n");
  • 44. Delete example /* quote string */ $title = $dbh->quote('Refactoring'); /* Delete a book */ $count = $dbh->exec("DELETE FROM bookshelf WHERE title = $title"); /* Return number of rows that were deleted */ print("Deleted $count rows.n");
  • 45. In almost all cases, favor prepared statements over PDO::exec()
  • 46. Prepared statements • To know them is to love them • No more SQL injection • Can execute same statement multiple times with different values • Efficient (in most cases) • Positional, named • The one feature PDO emulates
  • 47. Prepared statements Using named parameters: $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->bindParam('title', $title); $statement->bindParam('author', $author); $books = array( "Clean Code" => "Robert C. Martin", "Refactoring" => "Martin Fowler", "Test-Driven Development" => "Kent Beck", "The Agile Samurai" => "Jonathan Rasmusson", "Working Effectively with Legacy Code" => "Michael Feathers" ); foreach ($books as $title => $author) { $setup->execute(); }
  • 48. Prepared statements Using named parameters: $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->bindParam('title', $title); $statement->bindParam('author', $author); $books = array( "Clean Code" => "Robert C. Martin", "Refactoring" => "Martin Fowler", "Test-Driven Development" => "Kent Beck", "The Agile Samurai" => "Jonathan Rasmusson", "Working Effectively with Legacy Code" => "Michael Feathers" ); foreach ($books as $title => $author) { $setup->execute(); }
  • 49. Prepared statements Using named parameters: $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->bindParam('title', $title); $statement->bindParam('author', $author); $books = array( "Clean Code" => "Robert C. Martin", "Refactoring" => "Martin Fowler", "Test-Driven Development" => "Kent Beck", "The Agile Samurai" => "Jonathan Rasmusson", "Working Effectively with Legacy Code" => "Michael Feathers" ); foreach ($books as $title => $author) { $setup->execute(); }
  • 50. Prepared statements Using named parameters: $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->bindParam('title', $title); $statement->bindParam('author', $author); $books = array( "Clean Code" => "Robert C. Martin", "Refactoring" => "Martin Fowler", "Test-Driven Development" => "Kent Beck", "The Agile Samurai" => "Jonathan Rasmusson", "Working Effectively with Legacy Code" => "Michael Feathers" ); foreach ($books as $title => $author) { $setup->execute(); }
  • 51. Prepared statements Using positional parameters: $sql = "INSERT INTO bookshelf (title, author) VALUES (?, ?)"; $statement = $dbh->prepare($sql); $statement->bindParam(1, $title); $statement->bindParam(2, $author); $books = array( "Clean Code" => "Robert C. Martin", "Refactoring" => "Martin Fowler", "Test-Driven Development" => "Kent Beck", "The Agile Samurai" => "Jonathan Rasmusson", "Working Effectively with Legacy Code" => "Michael Feathers" ); foreach ($books as $title => $author) { $setup->execute(); }
  • 52. Prepared statements Array of named params to PDO::execute $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->execute(array('title' => $title, 'author' => $author));
  • 53. Prepared statements Array of named params to PDO::execute $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->execute(array('title' => $title, 'author' => $author));
  • 54. Prepared statements Array of named params to PDO::execute $sql = "INSERT INTO bookshelf (title, author) VALUES (:title, :author)"; $statement = $dbh->prepare($sql); $statement->execute(array('title' => $title, 'author' => $author));
  • 55. Select • Gets data from the database • Results returned as PDOStatement • How data is fetched from statement depends on fetch mode • Grab all results at once with fetchAll()
  • 56. Fetch modes • Can be set in constructor or later with PDO::setAttribute() or PDOStatement::setFetchMode() • PDO::FETCH_ASSOC • PDO::FETCH_BOTH (default) • PDO::FETCH_NUM • PDO::FETCH_OBJ • to name a few . . .
  • 57. Fetching // Gets all books in database $stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title"); // Returns array of all results $books = $stmt->fetchAll(); // Returns next row in manner determined by fetch mode $row = $stmt->fetch(); // Can choose fetch mode at time of fetch $row = $stmt->fetch(PDO::FETCH_OBJ);
  • 58. Fetching // Gets all books in database $stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title"); // Returns array of all results $books = $stmt->fetchAll(); // Returns next row in manner determined by fetch mode $row = $stmt->fetch(); // Can choose fetch mode at time of fetch $row = $stmt->fetch(PDO::FETCH_OBJ);
  • 59. Fetching // Gets all books in database $stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title"); // Returns array of all results $books = $stmt->fetchAll(); // Returns next row in manner determined by fetch mode $row = $stmt->fetch(); // Can choose fetch mode at time of fetch $row = $stmt->fetch(PDO::FETCH_OBJ);
  • 60. Fetching // Gets all books in database $stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title"); // Returns array of all results $books = $stmt->fetchAll(); // Returns next row in manner determined by fetch mode $row = $stmt->fetch(); // Can choose fetch mode at time of fetch $row = $stmt->fetch(PDO::FETCH_OBJ);
  • 61. Fetching // Gets all books in database $stmt = $dbh->query("SELECT * FROM bookshelf ORDER BY title"); // Returns array of all results $books = $stmt->fetchAll(); // Returns next row in manner determined by fetch mode $row = $stmt->fetch(); // Can choose fetch mode at time of fetch $row = $stmt->fetch(PDO::FETCH_OBJ);
  • 62. Fetching PDOStatement implements Traversable, which allows you to: $stmt = $dbh->query('SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($stmt as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 63. Fetching PDOStatement implements Traversable, which allows you to: $stmt = $dbh->query('SELECT * FROM bookshelf ORDER BY title'); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php foreach ($stmt as $row) { echo "<tr>"; echo "<td>{$row['title']}</td><td>{$row['author']}</td>"; echo "</tr>"; } ?> </table>
  • 64. Fetching PDO::FETCH_BOUND is slick $stmt = $dbh->query('SELECT id, title, author FROM bookshelf ORDER BY title'); $stmt->bindColumn('title', $title); $stmt->bindColumn('author', $author); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($stmt->fetch(PDO::FETCH_BOUND)) { echo "<tr>"; echo "<td>$title</td><td>$author</td>"; echo "</tr>"; } ?> </table>
  • 65. Fetching PDO::FETCH_BOUND is slick $stmt = $dbh->query('SELECT id, title, author FROM bookshelf ORDER BY title'); $stmt->bindColumn('title', $title); $stmt->bindColumn('author', $author); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($stmt->fetch(PDO::FETCH_BOUND)) { echo "<tr>"; echo "<td>$title</td><td>$author</td>"; echo "</tr>"; } ?> </table>
  • 66. Fetching PDO::FETCH_BOUND is slick $stmt = $dbh->query('SELECT id, title, author FROM bookshelf ORDER BY title'); $stmt->bindColumn('title', $title); $stmt->bindColumn('author', $author); ?> <table> <tr> <th>Title</th><th>Author</th> </tr> <?php while ($stmt->fetch(PDO::FETCH_BOUND)) { echo "<tr>"; echo "<td>$title</td><td>$author</td>"; echo "</tr>"; } ?> </table>
  • 68. PDO::lastInsertId() • Returns the ID of the last inserted row • Or the last value from a sequence object • Be careful, some databases don’t support this and may exhibit unexpected behavior
  • 69. Transactions • PDO::beginTransaction() • PDO::commit() • PDO::rollback() • Check your DB documentation for support
  • 70. Benefits • Maintainability • Portability (with a few vendor specific caveats) • Safety (prepared statements) • Object oriented
  • 71. Drawbacks • Not all vendor specific features supported • Interface is almost the same for all databases • Slower in some cases • Mediocre Oracle support (who uses Oracle?)
  • 72. Portable, mostly • Every DB has its own oddities and gotchas • PDO offers data access abstraction • You’ll likely still have to tweak if you’re doing anything other than very simple CRUD • Still better than mysql_*, mysqli_*, sqlsrv_* • Choose a DBAL like Doctrine if you need more
  • 73. Credits • PHP Data Objects by Wez Furlong: http:// www.slideshare.net/wezfurlong/php-data-objects • Nettuts+: http://net.tutsplus.com/tutorials/php/why-you- should-be-using-phps-pdo-for-database-access/ • Introduction to PDO: http://www.dreamincode.net/ forums/topic/214733-introduction-to-pdo/ • php.net: http://us.php.net/manual/en/class.pdo.php
  • 75. Thanks! • @JeremyKendall • [email protected] http://about.me/jeremykendall

Editor's Notes