Can’t Miss Features of
    PHP 5.3 and 5.4

Jeff Carouth       BCSPHP Sept. 15, 2011


               1
Hi! I am Jeff

Senior Developer at Texas A&M
Author of several magazine articles (php|architect)
Infrequent (lazy) blogger at carouth.com
Lover of progress, innovation, and improvement.
Developing with PHP since ~2003



                       2
About you?


New to PHP?
Using PHP 5.3?
Used PHP yesterday? this afternoon?




                     3
PHP 5.3




   4
What’s all the hubbub?


__DIR__
SPL improvements
Closures / anonymous functions / lambda functions
Namespaces




                     5
__DIR__
“under under durrr”




         6
__DIR__ usefulness

   Cleanup autoloading code.
   That’s about it.



include_once dirname(__FILE__) . "/../myfile.php";


include_once __DIR__ . "/../myfile.php";




                               7
SPL Improvements


SPLFixedArray

SPLDoublyLinkedList

SPLStack and SPLQueue

SPLHeap, SPLMinHeap, SPLMaxHeap

SPLPriorityQueue




                        8
We have shiny new data
structures. Use them instead of
   arrays where appropriate!



               9
Closures



   10
The PHP folk are trying to
     confuse you…



            11
...because not all
anonymous functions are
        closures...


           12
…which aren’t the same as
 lambda expressions or
       functors.


            13
You say semantics? No.
        There is a difference.

(But I’ll step off my soapbox for now. Feel free to ping
                        me later.)

                           14
function() {
    print 'Hello';
};



$myhello = function() {
    print "Hello!";
};

$myhello();




$myhelloname = function($name) {
    print "Hello, " . $name . "!";
};

$myhelloname('BCSPHP');


                             15
function get_closure($name) {
    $person = new stdclass();
    $person->name = $name;

      return function() use($person) {
          print "Hello, " . $person->name . "!";
      };
}

$myhelloclosure = get_closure('Gernonimo');
$myhelloClosure();
// Output: "Hello, Geronimo!"




     $myhelloclosure is said to “close over” the
    $person variable which is within its defined scope.


                                16
Using Lambdas


array_walk, array_map, array_reduce
usort, uasort
array_filter
preg_replace_callback




                17
$fabrics= array(
    array('color'   =>   'blue'),
    array('color'   =>   'red'),
    array('color'   =>   'green'),
    array('color'   =>   'maroon')
);


usort($fabrics, function($a, $b) {
    return strcmp($a['color'], $b['color']);
});




                                 18
// filter based on dynamic criteria
define('MINUTE', 60);
define('HOUR', 3600);
define('DAY', 86400);
define('WEEK', 604800);
$accounts = array(
    array('id' => 1, 'lastActivity'   =>   time()-2*WEEK),
    array('id' => 2, 'lastActivity'   =>   time()-3*DAY),
    array('id' => 3, 'lastActivity'   =>   time()-45*MINUTE),
    array('id' => 4, 'lastActivity'   =>   time()-2*HOUR-5*MINUTE),
    array('id' => 5, 'lastActivity'   =>   time()-5),
    array('id' => 6, 'lastActivity'   =>   time()-3*MINUTE-20),
    array('id' => 7, 'lastActivity'   =>   time()-2*WEEK-3*DAY),
    array('id' => 8, 'lastActivity'   =>   time()-HOUR-33*MINUTE),
    array('id' => 9, 'lastActivity'   =>   time()-5*MINUTE),
);




                               19
$results = array();
$oneweek = time()-WEEK;
foreach ($accounts as $account) {
    if ($account['lastActivity'] > $oneweek) {
        $results[] = $account;
    }
}




$results = array_filter(
    $accounts,
    function($account) {
        return $account['lastActivity'] > time()-WEEK;
    }
);




                             20
$getfilterfunc = function($lower, $upper = 0) {
    $lowerTime = time() - $lower;
    $upperTime = time() - $upper;

    return function($account)
            use($lowerTime, $upperTime) {
        return $account['lastActivity'] >= $lowerTime
            && $account['lastActivity'] <= $upperTime;
    }
}

$pastWeekResults = array_filter(
    $accounts,
    $getfilterfunc(WEEK));
$previousWeekResults = array_filter(
    $accounts,
    $getFilterFunc(2*WEEK, WEEK));



                             21
BOOM!



22
MOAR PRACTICAL


Caching.
Typically you have a load() and save()
method.
Perhaps even a load(), start(), and end()
method.




                   23
class SimpleCache {
    private $_data = array();

    public function load($key) {
        if (!array_key_exists($key, $this->_data)) {
            return false;
        }
        return $this->_data[$key];
    }

    public function save($key, $data) {
        $this->_data[$key] = $data;
    }
}


$cache = new SimpleCache();
if (($data = $cache->load(‘alltags’)) === false) {
    $service = new ExpensiveLookupClass();
    $data = $service->findAllTags();
    $cache->save(‘alltags’, $data);
}

                                24
class SimpleCacheWithClosures {
    protected $_data = array();

    public function load($key, $callback) {
        if (!array_key_exists($key, $this->_data)) {
            $this->_data[$key] = $callback();
        }
        return $this->_data[$key];
    }
}


$cache = new SimpleCacheWithClosures();

$service = new ExpensiveLookupClass();
$data = $cache->load('alltags', function() use($service) {
    return $service->findAllTags();
});



                              25
Functors
Because the rest just wasn’t enough…




                 26
Functors, in simple terms,
are objects that you can call
  as if they are functions.


              27
class Send {
    private function _broadcast() {
        return 'Message sent.';
    }

    public function __invoke() {
        return $this->_broadcast();
    }
}

$send = new Send();
debug_log($send());




                             28
Namespaces


All the cool languages have them.
or perhaps PHP just wants to be JAVA
with all its package glory
after all, we do have PHARs




                       29
Nope. Namespaces solve a
       real need.



           30
The “” Separator



        31
Namespace Benefits


Organization. Both file and code.
Reduce conflicts with other libraries.
Shorten class names.
Readability.




                       32
define("LIBRARYDIR", __DIR__);

class Tamu_Cas_Adapter {
    function auth() { }
}

function tamu_cas_create_client() {
    return new Tamu_Http_Client();
}


namespace TamuCas;
use TamuHttpClient as HttpClient;

const LIBRARYDIR = __DIR__;

class Adapter {
    function auth() { }
}

function create_client() {
    return new HttpClient();
}
                               33
Namespace organization

In /path/to/Tamu.php:
namespace Tamu;



In /path/to/Tamu/Dmc.php
namespace TamuDmc;



In /path/to/Tamu/Auth/Adapter/Cas.php
namespace TamuAuthAdapter;
class Cas { }


                               34
Conflict Resolution

namespace My;
function str_split($string, $split_len = 2) {
    return "Nope. I don't like to split strings.";
}

$splitstr = str_split('The quick brown fox');
// $splitstr = "Nope. I don't like to split strings."

$splitstr = str_split('The quick brown fox');
// $splitstr = array('T', 'h', 'e', ..., 'o', 'x');




                             35
Class name shortening

class Zend_Application_Resource_Cachemanager
    extends Zend_Application_Resource_ResourceAbstract
{
    //...
}



namespace ZendApplicationResource;
class Cachemanager extends ResourceAbstract
{
    //...
}



                              36
Readability by Namespace


require_once "Zend/Http/Client.php";
$client = new Zend_Http_Client();


use ZendHttp;
$client = new Client();


use ZendHttpClient as HttpClient;
$httpClient = new HttpClient();




                             37
Take a deep breath
        38
PHP 5.4



alpha3 was used for demos
beta going to be packaged on Sep 14
(source:php-internals)




                     39
New Features

Closures support $this keyword
Short Array Syntax
Array Dereferencing
Traits
(Debug webserver)

                40
Closures and $this
class HelloWorldPrinter
{
    public function __construct($name) {
        $this->_name = $name;
    }

    public function getPrinter() {
        return function() {
            return "Hello, " . $this->_name . "!";
        };
    }
}


$instance = new HelloWorldPrinter('BCSPHP');
$printer = $instance->getPrinter();

echo $printer();
                             41
Prior to PHP 5.4
Fatal error: Using $this when not in object context in /
Users/jcarouth/Documents/code-bcsphp-092011/
php54closurethis.php on line 14




PHP 5.4.0alpha3 (built Aug 5, 2011)
Hello, BCSPHP!




                              42
Short Array Syntax
          Saving you a few keystrokes
and compute cycles when switching from JavaScript




                       43
Really, who doesn’t love
JavaScript array syntax?



           44
//empty array
$arr = [];

//simple array
$arr = [1, 2, 3];

//"dictionary" array
$arr = ['name' => 'jeff', 'language' => 'php'];

//multi-dimensional
$arr = [['orange', 'blue'], ['black', 'gold']];




                             45
Array Dereferencing
         46
$array = array(1, 2, 3);
$dereference = *$array;




                   Sorry, no pointers.
    All the upset C++ wizards, go have some pizza.




                           47
class UserDataSource
{
    public function getDataForJeff()
    {
        return [
            'id' => 1,
            'name' => 'Jeff Carouth',
            'isAdmin' => true,
        ];
    }
}


$jeff = $store->getDataForJeff();
if ($jeff['isAdmin'] === true) {
    //give him access to all the things
}
                                             PHP <= 5.3
if ($store->getDataForJeff()['isAdmin']) {
    //shorter...but be mindful
}
                             48
                                             PHP >= 5.4
Pitfalls


Dereferencing a non-existent key produces a
NOTICE.
If the function does not return an array,
unexpected behavior.




                       49
Traits!



   50
Definition

Traits is a mechanism for code reuse in single
inheritance languages such as PHP. A Trait is
intended to reduce some limitations of single
inheritance by enabling a developer to reuse
sets of methods freely in several independent
classes living in different class hierarchies. The
semantics of the combination of Traits and
classes is defined in a way, which reduces
complexity and avoids the typical problems
associated with multiple inheritance and Mixins.



                        51
A bit much to
      take in
The important bit is traits
allow developers like you to
increase code reuse and get
around limitations of single-
inheritance.



                                52
Show me the code!

trait Named {
    function name() {
        //function body
    }
}




                          53
class SearchController {
    public function findBook(Book $b) { }

    private function log($message) {
        error_log($message);
    }
}

class AdminController {
    public function grant(User $u, Privilege $p) { }

    private function log($message) {
        error_log($message);
    }
}




                             54
trait Logging {
    private function log($message) {
        error_log($message);
    }
}

class SearchController {
    use Logging;
}

class AdminController {
    use Logging;
}




                             55
namespace TamuTimesModels;
class Story {
    public function setDataStore($store) {
        $this->_ds = $store;
    }

    public function getDataStore() {
        return $this->_ds;
    }
}

class User {
    public function setDataStore($store) {
        $this->_ds = $store;
    }

    public function getDataStore() {
        return $this->_ds;
    }
}


                             56
namespace TamuDmcApp;
trait DataStore {
    public function setDataStore($store) {
        $this->_ds = $store;
    }

    public function getDataStore() {
        return $this->_ds;
    }
}

namespace TamuTimesModels;
use TamuDmcAppDataStore;
class Story {
    use DataStore;
}

class User {
    use DataStore;
}


                              57
namespace BCSPHP;
trait MessageBroadcast {
    public function sendMessage() { }

    abstract private function _formatMessage();
}

class MeetingNotification {
    use MessageBroadcast;

    private function _formatMessage() {
        return "Notice: BCSPHP Meeting " . $this->_date;
    }
}




                              58
Traits are “just compiler
assisted copy and paste.”
      - Stefan Marr, PHP Internals Mailing List, Nov 2010




                  59
Built-in Development Server




             60
DEMO

php -S 0.0.0.0:8080 -t /path/to/docroot




                        61
Caveat

       Routing must be handled with a separate
       router.php script.

if (file_exists(__DIR__ . '/' . $_SERVER['REQUEST_URI'])) {
    return false; // serve the requested resource as-is.
} else {
    include_once 'index.php';
}


if (php_sapi_name() == 'cli-server') {
    /* route static assets and return false */
}

                             62
What you can do now:


(more like what you should do)
Test PHP 5.4 — http://qa.php.net
Run    make test
TEST YOUR APPS against PHP 5.4-alpha/beta/RC




                     63
That’s all folks!

QUESTIONS?

@jcarouth

jcarouth@gmail.com

jeffcarouth.info



                     64
Have feedback?

http://joind.in/3716




          65
Resources


Enygma’s PHP 5.3 example code
http://bit.ly/q9Eu36
Elazar’s benchmarks of SPL features in PHP 5.3
http://bit.ly/nKsbvQ
PHP documentation on the built-in web server
http://bit.ly/rc26l0



                      66

Can't Miss Features of PHP 5.3 and 5.4

  • 1.
    Can’t Miss Featuresof PHP 5.3 and 5.4 Jeff Carouth BCSPHP Sept. 15, 2011 1
  • 2.
    Hi! I amJeff Senior Developer at Texas A&M Author of several magazine articles (php|architect) Infrequent (lazy) blogger at carouth.com Lover of progress, innovation, and improvement. Developing with PHP since ~2003 2
  • 3.
    About you? New toPHP? Using PHP 5.3? Used PHP yesterday? this afternoon? 3
  • 4.
  • 5.
    What’s all thehubbub? __DIR__ SPL improvements Closures / anonymous functions / lambda functions Namespaces 5
  • 6.
  • 7.
    __DIR__ usefulness Cleanup autoloading code. That’s about it. include_once dirname(__FILE__) . "/../myfile.php"; include_once __DIR__ . "/../myfile.php"; 7
  • 8.
    SPL Improvements SPLFixedArray SPLDoublyLinkedList SPLStack andSPLQueue SPLHeap, SPLMinHeap, SPLMaxHeap SPLPriorityQueue 8
  • 9.
    We have shinynew data structures. Use them instead of arrays where appropriate! 9
  • 10.
  • 11.
    The PHP folkare trying to confuse you… 11
  • 12.
    ...because not all anonymousfunctions are closures... 12
  • 13.
    …which aren’t thesame as lambda expressions or functors. 13
  • 14.
    You say semantics?No. There is a difference. (But I’ll step off my soapbox for now. Feel free to ping me later.) 14
  • 15.
    function() { print 'Hello'; }; $myhello = function() { print "Hello!"; }; $myhello(); $myhelloname = function($name) { print "Hello, " . $name . "!"; }; $myhelloname('BCSPHP'); 15
  • 16.
    function get_closure($name) { $person = new stdclass(); $person->name = $name; return function() use($person) { print "Hello, " . $person->name . "!"; }; } $myhelloclosure = get_closure('Gernonimo'); $myhelloClosure(); // Output: "Hello, Geronimo!" $myhelloclosure is said to “close over” the $person variable which is within its defined scope. 16
  • 17.
    Using Lambdas array_walk, array_map,array_reduce usort, uasort array_filter preg_replace_callback 17
  • 18.
    $fabrics= array( array('color' => 'blue'), array('color' => 'red'), array('color' => 'green'), array('color' => 'maroon') ); usort($fabrics, function($a, $b) { return strcmp($a['color'], $b['color']); }); 18
  • 19.
    // filter basedon dynamic criteria define('MINUTE', 60); define('HOUR', 3600); define('DAY', 86400); define('WEEK', 604800); $accounts = array( array('id' => 1, 'lastActivity' => time()-2*WEEK), array('id' => 2, 'lastActivity' => time()-3*DAY), array('id' => 3, 'lastActivity' => time()-45*MINUTE), array('id' => 4, 'lastActivity' => time()-2*HOUR-5*MINUTE), array('id' => 5, 'lastActivity' => time()-5), array('id' => 6, 'lastActivity' => time()-3*MINUTE-20), array('id' => 7, 'lastActivity' => time()-2*WEEK-3*DAY), array('id' => 8, 'lastActivity' => time()-HOUR-33*MINUTE), array('id' => 9, 'lastActivity' => time()-5*MINUTE), ); 19
  • 20.
    $results = array(); $oneweek= time()-WEEK; foreach ($accounts as $account) { if ($account['lastActivity'] > $oneweek) { $results[] = $account; } } $results = array_filter( $accounts, function($account) { return $account['lastActivity'] > time()-WEEK; } ); 20
  • 21.
    $getfilterfunc = function($lower,$upper = 0) { $lowerTime = time() - $lower; $upperTime = time() - $upper; return function($account) use($lowerTime, $upperTime) { return $account['lastActivity'] >= $lowerTime && $account['lastActivity'] <= $upperTime; } } $pastWeekResults = array_filter( $accounts, $getfilterfunc(WEEK)); $previousWeekResults = array_filter( $accounts, $getFilterFunc(2*WEEK, WEEK)); 21
  • 22.
  • 23.
    MOAR PRACTICAL Caching. Typically youhave a load() and save() method. Perhaps even a load(), start(), and end() method. 23
  • 24.
    class SimpleCache { private $_data = array(); public function load($key) { if (!array_key_exists($key, $this->_data)) { return false; } return $this->_data[$key]; } public function save($key, $data) { $this->_data[$key] = $data; } } $cache = new SimpleCache(); if (($data = $cache->load(‘alltags’)) === false) { $service = new ExpensiveLookupClass(); $data = $service->findAllTags(); $cache->save(‘alltags’, $data); } 24
  • 25.
    class SimpleCacheWithClosures { protected $_data = array(); public function load($key, $callback) { if (!array_key_exists($key, $this->_data)) { $this->_data[$key] = $callback(); } return $this->_data[$key]; } } $cache = new SimpleCacheWithClosures(); $service = new ExpensiveLookupClass(); $data = $cache->load('alltags', function() use($service) { return $service->findAllTags(); }); 25
  • 26.
    Functors Because the restjust wasn’t enough… 26
  • 27.
    Functors, in simpleterms, are objects that you can call as if they are functions. 27
  • 28.
    class Send { private function _broadcast() { return 'Message sent.'; } public function __invoke() { return $this->_broadcast(); } } $send = new Send(); debug_log($send()); 28
  • 29.
    Namespaces All the coollanguages have them. or perhaps PHP just wants to be JAVA with all its package glory after all, we do have PHARs 29
  • 30.
    Nope. Namespaces solvea real need. 30
  • 31.
  • 32.
    Namespace Benefits Organization. Bothfile and code. Reduce conflicts with other libraries. Shorten class names. Readability. 32
  • 33.
    define("LIBRARYDIR", __DIR__); class Tamu_Cas_Adapter{ function auth() { } } function tamu_cas_create_client() { return new Tamu_Http_Client(); } namespace TamuCas; use TamuHttpClient as HttpClient; const LIBRARYDIR = __DIR__; class Adapter { function auth() { } } function create_client() { return new HttpClient(); } 33
  • 34.
    Namespace organization In /path/to/Tamu.php: namespaceTamu; In /path/to/Tamu/Dmc.php namespace TamuDmc; In /path/to/Tamu/Auth/Adapter/Cas.php namespace TamuAuthAdapter; class Cas { } 34
  • 35.
    Conflict Resolution namespace My; functionstr_split($string, $split_len = 2) { return "Nope. I don't like to split strings."; } $splitstr = str_split('The quick brown fox'); // $splitstr = "Nope. I don't like to split strings." $splitstr = str_split('The quick brown fox'); // $splitstr = array('T', 'h', 'e', ..., 'o', 'x'); 35
  • 36.
    Class name shortening classZend_Application_Resource_Cachemanager extends Zend_Application_Resource_ResourceAbstract { //... } namespace ZendApplicationResource; class Cachemanager extends ResourceAbstract { //... } 36
  • 37.
    Readability by Namespace require_once"Zend/Http/Client.php"; $client = new Zend_Http_Client(); use ZendHttp; $client = new Client(); use ZendHttpClient as HttpClient; $httpClient = new HttpClient(); 37
  • 38.
    Take a deepbreath 38
  • 39.
    PHP 5.4 alpha3 wasused for demos beta going to be packaged on Sep 14 (source:php-internals) 39
  • 40.
    New Features Closures support$this keyword Short Array Syntax Array Dereferencing Traits (Debug webserver) 40
  • 41.
    Closures and $this classHelloWorldPrinter { public function __construct($name) { $this->_name = $name; } public function getPrinter() { return function() { return "Hello, " . $this->_name . "!"; }; } } $instance = new HelloWorldPrinter('BCSPHP'); $printer = $instance->getPrinter(); echo $printer(); 41
  • 42.
    Prior to PHP5.4 Fatal error: Using $this when not in object context in / Users/jcarouth/Documents/code-bcsphp-092011/ php54closurethis.php on line 14 PHP 5.4.0alpha3 (built Aug 5, 2011) Hello, BCSPHP! 42
  • 43.
    Short Array Syntax Saving you a few keystrokes and compute cycles when switching from JavaScript 43
  • 44.
    Really, who doesn’tlove JavaScript array syntax? 44
  • 45.
    //empty array $arr =[]; //simple array $arr = [1, 2, 3]; //"dictionary" array $arr = ['name' => 'jeff', 'language' => 'php']; //multi-dimensional $arr = [['orange', 'blue'], ['black', 'gold']]; 45
  • 46.
  • 47.
    $array = array(1,2, 3); $dereference = *$array; Sorry, no pointers. All the upset C++ wizards, go have some pizza. 47
  • 48.
    class UserDataSource { public function getDataForJeff() { return [ 'id' => 1, 'name' => 'Jeff Carouth', 'isAdmin' => true, ]; } } $jeff = $store->getDataForJeff(); if ($jeff['isAdmin'] === true) { //give him access to all the things } PHP <= 5.3 if ($store->getDataForJeff()['isAdmin']) { //shorter...but be mindful } 48 PHP >= 5.4
  • 49.
    Pitfalls Dereferencing a non-existentkey produces a NOTICE. If the function does not return an array, unexpected behavior. 49
  • 50.
  • 51.
    Definition Traits is amechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way, which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins. 51
  • 52.
    A bit muchto take in The important bit is traits allow developers like you to increase code reuse and get around limitations of single- inheritance. 52
  • 53.
    Show me thecode! trait Named { function name() { //function body } } 53
  • 54.
    class SearchController { public function findBook(Book $b) { } private function log($message) { error_log($message); } } class AdminController { public function grant(User $u, Privilege $p) { } private function log($message) { error_log($message); } } 54
  • 55.
    trait Logging { private function log($message) { error_log($message); } } class SearchController { use Logging; } class AdminController { use Logging; } 55
  • 56.
    namespace TamuTimesModels; class Story{ public function setDataStore($store) { $this->_ds = $store; } public function getDataStore() { return $this->_ds; } } class User { public function setDataStore($store) { $this->_ds = $store; } public function getDataStore() { return $this->_ds; } } 56
  • 57.
    namespace TamuDmcApp; trait DataStore{ public function setDataStore($store) { $this->_ds = $store; } public function getDataStore() { return $this->_ds; } } namespace TamuTimesModels; use TamuDmcAppDataStore; class Story { use DataStore; } class User { use DataStore; } 57
  • 58.
    namespace BCSPHP; trait MessageBroadcast{ public function sendMessage() { } abstract private function _formatMessage(); } class MeetingNotification { use MessageBroadcast; private function _formatMessage() { return "Notice: BCSPHP Meeting " . $this->_date; } } 58
  • 59.
    Traits are “justcompiler assisted copy and paste.” - Stefan Marr, PHP Internals Mailing List, Nov 2010 59
  • 60.
  • 61.
    DEMO php -S 0.0.0.0:8080-t /path/to/docroot 61
  • 62.
    Caveat Routing must be handled with a separate router.php script. if (file_exists(__DIR__ . '/' . $_SERVER['REQUEST_URI'])) { return false; // serve the requested resource as-is. } else { include_once 'index.php'; } if (php_sapi_name() == 'cli-server') { /* route static assets and return false */ } 62
  • 63.
    What you cando now: (more like what you should do) Test PHP 5.4 — http://qa.php.net Run make test TEST YOUR APPS against PHP 5.4-alpha/beta/RC 63
  • 64.
  • 65.
  • 66.
    Resources Enygma’s PHP 5.3example code http://bit.ly/q9Eu36 Elazar’s benchmarks of SPL features in PHP 5.3 http://bit.ly/nKsbvQ PHP documentation on the built-in web server http://bit.ly/rc26l0 66

Editor's Notes