PHP in 2013
Adam Harvey
@LGnome
Why PHP sucks a little less
this year than last
Adam Harvey
@LGnome
Branches
PHP 5.4
PHP 5.4
PHP 5.4
PHP 5.5
New features
Bling
BIT of BLING! by marragem (CC-BY-SA 2.0)
Generators
Generators
Generators
class RangeIterator implements Iterator { private $start; private $limit; private $step; private $current; public function __construct($start, $limit, $step = 1) { $this->start = $start; $this->limit = $limit; $this->step = $step; $this->current = $start; } public function current() { return $this->current; } public function key() { return ($this->current - $this->start) / $this->step; } public function next() { $this->current += $this->step; } public function rewind() { $this->current = $this->start; } public function valid() { return ($this->current >= $this->start && $this->current <= $this->limit); } } function xrange($start, $limit, $step = 1) { return new RangeIterator($start, $limit, $step); }
Generators
function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { yield $i; } }
Generators
A scoundrel
Han Solo trapped in the carbonite by Luigi Rosa (CC-BY-SA 2.0)
Generators
function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { yield $i; } } foreach (xrange(1, 9, 2) as $number) { echo "$number\n"; }
1
3
5
7
9
Generators
(yield $key => $value); yield;
Generators
function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { $command = (yield $i); if ($command == 'stop') { return; } } }
Generators
$gen = xrange(1, 9, 2); foreach ($gen as $number) { echo "$number\n"; $gen->send('stop'); }
1
Generators
function this_week() { $date = new DateTimeImmutable('6 days ago'); $now = new DateTimeImmutable; while ($date <= $now) { $formatted = $date->format('Y-m-d'); (yield $date => $formatted); $date = $date->add(new DateInterval('P1D')); } }
Generators
foreach (this_week() as $dt => $formatted) { echo $dt->format(DateTime::ISO8601)."\n"; }
Generators
function this_week() { $date = new DateTimeImmutable('6 days ago'); $now = new DateTimeImmutable; while ($date <= $now) { $formatted = $date->format('Y-m-d'); (yield $date => $formatted); $date = $date->add(new DateInterval('P1D')); } }
Generators
2013-11-02T07:18:59-0700 2013-11-03T07:18:59-0800 2013-11-04T07:18:59-0800 2013-11-05T07:18:59-0800 2013-11-06T07:18:59-0800 2013-11-07T07:18:59-0800 2013-11-08T07:18:59-0800
Finally, finally
Finally, finally
function do_something() { $temp = tempnam('/tmp', 'foo'); try { ... unlink($temp); } catch (FrameworkException $e) { ... unlink($temp); } catch (Exception $e) { unlink($temp); throw $e; } }
Finally, finally
class TemporaryFile { function __construct($directory, $prefix) { $this->file = tempnam($directory, $prefix); } function __destruct() { unlink($this->file); } function __toString() { return $this->file; } } function do_something() { $temp = new TemporaryFile('/tmp, 'foo'); try { ... } catch (FrameworkException $e) { ... } }
Finally, finally
function do_something() { $temp = tempnam('/tmp', 'FOO'); try { ... } catch (FrameworkException $e) { ... } finally { unlink($temp); } }
Finally, finally
function f() { try { return 'try'; } finally { return 'finally'; } } echo f();
finally
Password hashing
Password hashing
echo crypt('foo', '$2a$01234567890123456789a');
$2zJyhpjk3l9E
Password hashing
password_hash($password, $algo, $options) password_verify($password, $hash) password_get_info($hash) password_needs_rehash($hash, $algo, $options)
Password hashing
// Creating a hash: $hash = password_hash($passwd, PASSWORD_DEFAULT); // Verifying a password: if (password_verify($passwd, $hash)) { // do stuff }
Password hashing
$2y$10$6z7GKa9kpDN7KC3ICW1Hi.fdO/to7Y/x36WUKNPOIndHdkdR9Ae3K
Password hashing
$2y$10$6z7GKa9kpDN7KC3ICW1Hi.fdO/to7Y/x36WUKNPOIndHdkdR9Ae3K Hash type
Password hashing
$2y$10$6z7GKa9kpDN7KC3ICW1Hi.fdO/to7Y/x36WUKNPOIndHdkdR9Ae3K Hash options
Password hashing
$2y$10$6z7GKa9kpDN7KC3ICW1Hi.fdO/to7Y/x36WUKNPOIndHdkdR9Ae3K Randomly generated salt
Password hashing
$2y$10$6z7GKa9kpDN7KC3ICW1Hi.fdO/to7Y/x36WUKNPOIndHdkdR9Ae3K Hashed data
Password hashing
Password hashing
// Verifying a password: if (password_verify($passwd, $hash)) { // do stuff if (password_needs_rehash($hash, PASSWORD_DEFAULT)) { // rehash with password_hash() and save } }
Password hashing
OPcache
OPcache
zend_extension=${extension_dir}/opcache.so
OPcache
opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=4000 opcache.revalidate_freq=60 opcache.fast_shutdown=1 opcache.enable_cli=1 http://php.net/opcache.installation
OPcache
5.4 5.5 5.5 + OPcache
php.net 78.77 77.23 134.09
Laravel 4.0.9 30.07 29.51 161.83
WordPress 3.7.1 9.27 9.44 31.66
Requests per second
mod_php on Apache 2.2.16
foreach unpacking
$array = [[1, 2], [3, 4]]; foreach ($array as $item) { list($a, $b) = $item; // ... }
foreach unpacking
$array = [[1, 2], [3, 4]]; foreach ($array as list($a, $b)) { // ... }
empty()
empty(my_function());
Literal dereferencing
var_dump([1, 2, 3][0]); var_dump('PHP'[0]);
Literal dereferencing
var_dump([1, 2, 3][0]); var_dump('PHP'[0]); 1 P
::class
namespace Name\Space; class ClassName {} echo ClassName::class;
::class
namespace Name\Space; class ClassName {} echo ClassName::class; Name\Space\ClassName
Immutable DateTime
Backward incompatibilities
A car reverses; crumple zones are required now; no-one is happy
car accident.jpg by Jeremy Noble (CC-BY 2.0)
Windows support
Case insensitivity
i = I
I = i
i = İ
I = ı
$dbh->lastInsertId();
$dbh->lastinsertid();
$dbh->lastınsertıd();
Case insensitivity
Case insensitivity
function función() {} FUNCIÓN();
pack() and unpack()
Deprecated features
Suraxanı. Say that ten times fast
Oil Well in Suraxanı by me (WTFPL)
mysql_connect()
Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead
The Scream, by Munch
Scream by Christopher Macsurak (CC-BY 2.0)
(The original is by Edvard Munch, obviously)
Use PDO
mysql → PDO
$db = mysql_connect('localhost', 'user', 'pass'); mysql_select_db('db', $db); $id = mysql_real_escape_string($_GET['id'], $db); $st = mysql_query("SELECT name FROM user WHERE id = $id"); while ($row = mysql_fetch_assoc($st)) { echo "Hi, $row[name]!"; }
mysql → PDO
$db = mysql_connect('localhost', 'user', 'pass'); mysql_select_db('db', $db); $id = mysql_real_escape_string($_GET['id'], $db); $st = mysql_query("SELECT name FROM user WHERE id = $id"); while ($row = mysql_fetch_assoc($st)) { echo "Hi, $row[name]!"; }
mysql → PDO
$db = new PDO('mysql:host=localhost;dbname=db', 'user', 'pass'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $st = $db->prepare('SELECT name FROM user WHERE id = :id'); $st->execute(['id' => $_GET['id']]); while ($row = $st->fetch(PDO::FETCH_ASSOC)) { echo "Hi, $row[name]!"; }
preg_replace() /e modifier
preg_replace( '(<h([1-6])>(.*?)</h\1>)e', '"<h$1>" . strtoupper("$2") . "</h$1>"', $html );
preg_replace() /e modifier
preg_replace_callback( '(<h([1-6])>(.*?)</h\1>)', eval('"<h$1>" . strtoupper("$2") . "</h$1>"'), $html )
preg_replace() /e modifier
preg_replace_callback( '(<h([1-6])>(.*?)</h\1>)', eval('"<h$1>" . strtoupper("$2") . "</h$1>"'), $html )
preg_replace() /e modifier
preg_replace_callback( '(<h([1-6])>(.*?)</h\1>)', function (array $matches) { return "<h$matches[1]>" .strtoupper($matches[2]) ."</h$matches[1]>"; }, $html )
That's awesome, but how do I get this?
Compiling
xkcd: Compiling (CC-BY-NC 2.5)
Getting PHP 5.5
Getting PHP 5.5
Getting PHP 5.5
Getting PHP 5.5
PuPHPet
PHP 5.6
Flux capacitor
San Diego Comic-Con 2011 - Back to the Future flux capacitor (Profiles in History booth) by Doug Kline (CC-BY 2.0)
Variadic functions
function query($query, ...$params) { foreach ($params as $param) { $this->setParameter($param); } }
Variadic functions
function query($query, DateTime ...$params) { foreach ($params as $param) { $this->setParameter($param); } }
Variadic functions
function query($query, DateTime &...$params) { foreach ($params as $param) { $this->setParameter($param); } }
Variadic functions
Calls from incompatible context
class A { function foo() { // $this is B, not A } } class B { function bar() { A::foo(); } } (new B)->bar();
Deprecated: Non-static method A::foo() should not be called statically, assuming $this from incompatible context
Other hotness
Your feature here?
A window, open, veritably bursting with opportunities
Open Window by oatsy40
Questions?