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

PPTX
Php functions
PPT
Html ppt
PDF
Pl/sql - interaction avec la base de données & structures de contrôle
PDF
PHP - PDO.pdf
PPT
JavaScript Objects
PPT
Dom JavaScript
PPTX
HTML Forms
PPTX
Css tables
Php functions
Html ppt
Pl/sql - interaction avec la base de données & structures de contrôle
PHP - PDO.pdf
JavaScript Objects
Dom JavaScript
HTML Forms
Css tables

What's hot (20)

PPTX
Introduction to HTML.pptx
PDF
CSS notes
PPT
Xquery
PDF
Bca sem 6 php practicals 1to12
PDF
Fast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
PDF
HTML PPT.pdf
PDF
POCO C++ Libraries Intro and Overview
PPT
Bash shell
PPTX
Método de Búsqueda Hash
PDF
Lazy vs. Eager Loading Strategies in JPA 2.1
PDF
Introduction to JCR
PPTX
PDF
ZeroMQ Is The Answer
PDF
PythonOOP
PDF
CSS framework By Palash
PPT
PHP - Introduction to PHP AJAX
PPT
Frames tables forms
PDF
jQuery for beginners
PPTX
Html ppt
PPTX
Introduction to HTML.pptx
CSS notes
Xquery
Bca sem 6 php practicals 1to12
Fast Insight from Fast Data: Integrating ClickHouse and Apache Kafka
HTML PPT.pdf
POCO C++ Libraries Intro and Overview
Bash shell
Método de Búsqueda Hash
Lazy vs. Eager Loading Strategies in JPA 2.1
Introduction to JCR
ZeroMQ Is The Answer
PythonOOP
CSS framework By Palash
PHP - Introduction to PHP AJAX
Frames tables forms
jQuery for beginners
Html ppt
Ad

Viewers also liked (16)

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
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 - PDO Objects
PHP Data Objects
PHP WTF
PHP 7 performances from PHP 5
PHP, Under The Hood - DPC
PHP 7 new engine
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)

PDF
The History of PHPersistence
DOC
Ex[1].3 php db connectivity
PPTX
Basics of Working with PHP and MySQL.pptx
ODP
Php 102: Out with the Bad, In with the Good
PPTX
UNIT V (5).pptx
PPTX
Database Connectivity MYSQL by Dr.C.R.Dhivyaa Kongu Engineering College
PPTX
chapter_Seven Database manipulation using php.pptx
PDF
Php (1)
PDF
PHP and Rich Internet Applications
PDF
Mysql & Php
PPTX
FYBSC IT Web Programming Unit V Advanced PHP and MySQL
DOC
TXT
Gta v savegame
PDF
php plus mysql
DOCX
Php update and delet operation
PPTX
Drupal7 dbtng
PDF
PHP and Rich Internet Applications
TXT
Shell.php
PPT
Php My Sql
DOCX
Latihan form login
The History of PHPersistence
Ex[1].3 php db connectivity
Basics of Working with PHP and MySQL.pptx
Php 102: Out with the Bad, In with the Good
UNIT V (5).pptx
Database Connectivity MYSQL by Dr.C.R.Dhivyaa Kongu Engineering College
chapter_Seven Database manipulation using php.pptx
Php (1)
PHP and Rich Internet Applications
Mysql & Php
FYBSC IT Web Programming Unit V Advanced PHP and MySQL
Gta v savegame
php plus mysql
Php update and delet operation
Drupal7 dbtng
PHP and Rich Internet Applications
Shell.php
Php My Sql
Latihan form login

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
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
cuic standard and advanced reporting.pdf
PPTX
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Review of recent advances in non-invasive hemoglobin estimation
PDF
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
PDF
Approach and Philosophy of On baking technology
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
Understanding_Digital_Forensics_Presentation.pptx
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
A Presentation on Artificial Intelligence
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPT
Teaching material agriculture food technology
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Encapsulation theory and applications.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Reach Out and Touch Someone: Haptics and Empathic Computing
cuic standard and advanced reporting.pdf
PA Analog/Digital System: The Backbone of Modern Surveillance and Communication
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
20250228 LYD VKU AI Blended-Learning.pptx
MYSQL Presentation for SQL database connectivity
Review of recent advances in non-invasive hemoglobin estimation
Bridging biosciences and deep learning for revolutionary discoveries: a compr...
Approach and Philosophy of On baking technology
Diabetes mellitus diagnosis method based random forest with bat algorithm
Understanding_Digital_Forensics_Presentation.pptx
Chapter 3 Spatial Domain Image Processing.pdf
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
A Presentation on Artificial Intelligence
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Teaching material agriculture food technology
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Encapsulation theory and applications.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

Editor's Notes