the history of phpersistence
DESCRIPTION
Persistence is one of the most important part in a PHP project. Persisting data to a database came with PHP/FI and its MySQL support. From native extensions and PHP4 database abstraction libraries to PDO and modern ORM frameworks, you will (re)discover how persistence has evolved during the last decade. This talk will also introduce the future of data persistence with the growing success of alternative storage engines.TRANSCRIPT
![Page 1: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/1.jpg)
![Page 2: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/2.jpg)
The History of PHPersistence
Hugo Hamon - @hhamon OSIDays November 2011
![Page 3: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/3.jpg)
PHP/FI
Where Everything Begins…
![Page 4: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/4.jpg)
1995
PHP/FI
![Page 5: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/5.jpg)
1995
Files handling
![Page 6: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/6.jpg)
$fp = fopen("/counter.txt","w+");$counter = fgets($fp,1024);$counter++;fputs($fp, $counter);fclose($fp);
![Page 7: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/7.jpg)
1995
Databases support
![Page 8: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/8.jpg)
$db = mysql_connect("localhost", "root", "secret"); $name = "bob"; $result = mysql( $db, "select * from table where firstname='$name'" ); $num = mysql_numrows($result); echo "$num records found!<p>";
![Page 9: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/9.jpg)
$i=0; while ($i<$num); echo mysql_result($result,$i,"lcase(fullname)"); echo "\n"; echo mysql_result($result,$i,"address"); echo "\n"; $i++; endwhile;
![Page 10: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/10.jpg)
PHP 3/4
Code Reusability
![Page 11: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/11.jpg)
User Functions
![Page 12: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/12.jpg)
function db_connect($database, $host, $user, $pwd); function db_fetch_single($dbh, $query); function db_fetch_all($dbh, $query); function db_insert($dbh, $table, $values); function db_update($dbh, $table, $values, $pk); function db_delete($dbh, $table, $pk); function db_list_fields($dbh, $table); function db_drop_table($dbh, $table);
![Page 13: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/13.jpg)
function db_connect($database, $host, $user, $pwd) { $dbh = mysql_connect($host, $user, $pwd); if (!$dbh) { die('Server unavailable: '. mysql_error()); } if (!mysql_select_db($database, $dbh)) { die("'$database' unavailable: ". mysql_error()); } return $dbh; }
![Page 14: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/14.jpg)
/** * Fetches a single record from a database * * @param resource $dbh The database handler * @param string $query A SQL query * @return array A single record as an array */ function db_fetch_single($dbh, $query) { return current(db_fetch_all($dbh, $query)); }
![Page 15: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/15.jpg)
function db_fetch_all($dbh, $query) { $result = mysql_query($query, $dbh); if (!$result) { die('Invalid query: '. mysql_error()); } $records = array(); while ($record = mysql_fetch_assoc($result)) { $records[] = $record; } return $records; }
![Page 16: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/16.jpg)
function db_insert($dbh, $table, array $values) { $data = array(); foreach ($values as $value) { $data[] = mysql_real_escape_string($value, $dbh); } $sql = sprintf("INSERT INTO `$table` (`%s`) VALUES ('%s')", implode('`, `', array_keys($values)), implode("', '", $data) ); $result = mysql_query($query, $dbh); if (!$result) { die('Invalid data to insert: '. mysql_error()); } return mysql_insert_id($dbh); }
![Page 17: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/17.jpg)
include 'lib/database.inc.php'; $dbh = db_connect('osidays'); $query = 'SELECT id, name FROM author'; $authors = db_fetch_all($dbh, $query); $author = db_fetch_single( $dbh, 'SELECT id, name FROM author WHERE id = 3' ); $id = db_insert($dbh, 'author', array( 'name' => 'Jules Verne' ));
![Page 18: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/18.jpg)
PHP 4
OOP & Reusability
![Page 19: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/19.jpg)
class Database { function Database($database, host, $user, $pwd); function disconnect(); function connect(); function free(); function getErrorMessage(); function getErrorCode(); function getLastInsertId(); function insert($table, array $values); function fetchAll($query); function fetchSingle($query); function query($query); function quote($string); function hasError(); function _collectError(); function _init(); }
![Page 20: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/20.jpg)
require 'lib/Database.php'; $db= &new Database('demo', 'localhost', 'root'); $q = 'SELECT id, name FROM author'; foreach ($db->fetchAll($q) as $author) { // ... } $db->free(); $db->disconnect();
![Page 21: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/21.jpg)
require 'lib/Database.php'; $db= &new Database('demo', 'localhost', 'root'); $q = 'SELECT id, name FROM author WHERE id = 1'; $author = $db->fetchSingle($q); $db->free(); $db->disconnect();
![Page 22: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/22.jpg)
require 'lib/Database.php'; $db= &new Database('demo', 'localhost', 'root'); $res = $db->insert('author', array( 'name' => 'Jules Vernes' )); if ($result) { $id = $db->getLastInsertId(); } $db->disconnect();
![Page 23: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/23.jpg)
PHP 4
Professional APIs
![Page 24: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/24.jpg)
DBAL
![Page 25: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/25.jpg)
• PEAR::DB
• ADOdb
• Metabase
• MDB
• MDB2
• Creole
![Page 26: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/26.jpg)
§ Multiple databases support
§ Uni!ed APIs
§ Prepared statements supports
§ Query caching
§ Security against SQL Injections
![Page 27: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/27.jpg)
PEAR MDB2
![Page 28: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/28.jpg)
$dsn = array( 'phptype' => 'mysql', 'username' => 'root', 'password' => '', 'hostspec' => 'localhost', 'database' => 'demo', ); $db = & MDB2::connect($dsn); $db->setFetchMode(MDB2_FETCHMODE_ASSOC); $rs = $db->queryAll('SELECT id, name FROM author'); $db->disconnect();
![Page 29: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/29.jpg)
ADOdb
![Page 30: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/30.jpg)
include('adodb.inc.php'); $db = NewADOConnection('mysql'); $db->Connect('localhost', 'root', 'password', 'demo'); $result = $db->Execute('SELECT id, name FROM author'); if ($result) { while (!$result->EOF) { echo 'ID: ', $result->fields[0] ,"\n"; echo 'Name:', $result->fields[1] ,"\n";
$result->MoveNext(); } }
![Page 31: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/31.jpg)
2004
PHP 5
![Page 32: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/32.jpg)
2005
PHP Data Object
![Page 33: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/33.jpg)
• PECL extension as of PHP 5.0.0
• Core extension since PHP 5.1.0 (11/2005)
• 12 official drivers as of today
• Extensible Object Oriented API
• Prepared statements & transaction support
• Stored procedures support
![Page 34: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/34.jpg)
![Page 35: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/35.jpg)
« PDO provides a data-access abstraction
layer, which means that, regardless of
which database you're using, you use the
same functions to issue queries and fetch
data. »
![Page 36: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/36.jpg)
« PDO does not provide a
database abstraction as it
doesn't rewrite SQL or emulate
missing features »
![Page 37: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/37.jpg)
Transactions /
Prepared Statements
![Page 38: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/38.jpg)
try { $pdo->beginTransaction(); $query = 'INSERT INTO author (name) VALUES (?)'; $stmt = $pdo->prepare($query); $stmt->bindValue(1, 'Jules Verne'); $stmt->execute(); $id = $pdo->lastInsertId(); $pdo->commit(); } catch (PDOException $e) { $pdo->rollback(); }
![Page 39: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/39.jpg)
Stored Procedures
![Page 40: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/40.jpg)
DELIMITER | CREATE PROCEDURE coming_events (IN start DATE, OUT events INT) BEGIN SELECT COUNT(*) INTO events FROM events WHERE start_at >= start; END |
$query = "CALL coming_events('2011-03-01', @events);"; $pdo->query($query); $stmt = $pdo->query("SELECT @events;"); echo $stmt->fetchColumn() ,' events to come.';
![Page 41: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/41.jpg)
PHP 5
Zend_Db
![Page 42: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/42.jpg)
Table Data Gateway
![Page 43: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/43.jpg)
class AuthorGateway extends Zend_Db_Table_Abstract { protected $_name = 'authors'; protected $_primary = 'author_id'; }
![Page 44: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/44.jpg)
$data = array( 'first_name' => 'Jules', 'last_name' => 'Vernes', ); $table = new AuthorGateway(); $table->insert($data);
![Page 45: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/45.jpg)
Row Data Gateway
![Page 46: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/46.jpg)
$table = new AuthorGateway(); // New empty row $row = $table->createRow(); // Insert a new row $row->firstName = 'Jules'; $row->lastName = 'Verne'; $row->save();
![Page 47: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/47.jpg)
Active Query
![Page 48: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/48.jpg)
$isbn = '1234567890'; $rows = $db->select() ->from(array('b' => 'books')) ->where('b.isbn = ?', $isbn) ->order(array('b.title ASC')) ->query() ->fetchAll() ;
![Page 49: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/49.jpg)
PHP 5
Object Relational Mapping
![Page 50: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/50.jpg)
• Use objects instead of raw SQL queries
• Database abstraction layer (not always)
• Relationships support
• Behaviors support (i18n, timestampable…)
• Querying API
• Error logging
![Page 51: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/51.jpg)
2005
Propel ORM
![Page 52: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/52.jpg)
$author = new Author(); $author->setFirstName("Leo"); $author->setLastName("Tolstoy"); $book = new Book(); $book->setTitle("War & Peace"); $book->setIsbn("0140444173"); $book->setAuthor($author); $book->save();
![Page 53: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/53.jpg)
$query = BookQuery::create() ->joinWith('Book.Author') ->joinWith('Book.Publisher') ->where('Author.firstName = ?', 'Leo') ->where('Author.lastName = ?', 'Tolstoï') ->orderByTitle() ->filterByPublishYear(2009) ->find() ;
![Page 54: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/54.jpg)
2009
Doctrine 1.x
![Page 55: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/55.jpg)
$books = Doctrine_Query::create() ->select('b.*, a.*, p.*') ->from('Book b') ->leftJoin('b.Author a') ->leftJoin('b.Publisher p') ->where('a.firstName = ?', 'Karl') ->andWhere('a.lastName = ?', 'Marx') ->orderBy('b.title ASC') ->execute() ;
![Page 56: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/56.jpg)
2009
PHP 5.3
![Page 57: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/57.jpg)
ORM Frameworks
![Page 58: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/58.jpg)
Doctrine2
![Page 59: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/59.jpg)
• Database Abstraction Layer
• Object Relational Mapping
• Schema management
• Migrations support
• XML & NoSQL databases support
![Page 60: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/60.jpg)
/** @Entity() */ class Author { /** * @Id() * @GeneratedValue() * @Column(type="integer") */ private $id; /** @Column(type="string", length="30") */ private $name; /** @ReferenceMany(targetDocument="BlogPost") */ private $posts = array(); }
![Page 61: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/61.jpg)
$post = new BlogPost(); $post->setTitle('My First Blog Post'); $post->setBody('Some content...'); $author = new Author(); $author->setName('Hugo Hamon'); $author->addPost($post); $em->persist($user); $em->persist($post); $dm->flush();
![Page 62: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/62.jpg)
Toward NoSQL…
![Page 63: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/63.jpg)
« Not Only SQL »
![Page 64: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/64.jpg)
abcdef Hugo Hamon Key Value
![Page 65: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/65.jpg)
FirstName: Hugo
LastName: Hamon
Role: Speaker
abcdef Key
Column 1
Column 2
Column 3
![Page 66: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/66.jpg)
Name: Hugo Hamon
Role: Speaker
abcdef
Skills
0: PHP
1: HTML
2: CSS
Key Document
![Page 67: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/67.jpg)
2009
MongoDB Driver
![Page 68: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/68.jpg)
• Cross-platform support
• Schemaless language
• BSON type support
• Binary !le storage support (GridFS)
• Master – slave replication support
• Sharding (horizontal scaling)
![Page 69: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/69.jpg)
$mongo = new Mongo(); $col = $mongo->selectDb('osidays')->books; $books = array( array('title' => 'Da Vinci Code'), array('title' => 'The Lost Symbol'), array('title' => 'Digital Fortress'), ); foreach ($books as $book) { $collection->insert($book); }
![Page 70: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/70.jpg)
What’s next… … for today and tomorrow?
![Page 71: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/71.jpg)
2011
PHP 5.3 ODM Frameworks
![Page 72: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/72.jpg)
![Page 73: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/73.jpg)
• ORM Layers for Mongodb
• Dealing with objects instead of arrays
• Relationships support
• Query abstraction
• GridFS support
• Query logging & caching
![Page 74: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/74.jpg)
$post = new BlogPost(); $post->setTitle('My First Blog Post'); $post->setBody('Some content...'); $author = new Author(); $author->setName('Hugo Hamon'); $author->setEmail('[email protected]'); $dm->persist($user); $user->addPost($post); $dm->flush();
![Page 75: The History of PHPersistence](https://reader036.vdocuments.net/reader036/viewer/2022081400/554f38eeb4c905471e8b4891/html5/thumbnails/75.jpg)
QuesAons?
92-98, boulevard Victor Hugo
92 115 Clichy Cedex
[email protected] (+33 (0)1 40 99 82 11)
sensiolabs.com - symfony.com – trainings.sensiolabs.com