Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[WNYRuby/Buffalo PHP] Ruby and PHP, Sitting in a tree: C.O.D.I.N.G.

[WNYRuby/Buffalo PHP] Ruby and PHP, Sitting in a tree: C.O.D.I.N.G.

Every day I meet Ruby developers who are still using PHP on a daily basis, either professionally or for fun — this talk aims to showcase some of its latest features that you might have missed which can make your life easier.

If the last time you looked at PHPs release notes they had recently released a revamped object model, you’ve missed out on a lot. PHP has grown up and it’s time for the way you work with it to mature also.

Best practices, mature tooling, and fancy new features all come together to make PHP a very different language to what you might have left behind.

Who knows, perhaps you’ll fall in like with it all over again.

Davey Shafik

December 10, 2013
Tweet

More Decks by Davey Shafik

Other Decks in Programming

Transcript

  1. Ruby and PHP
    Sitting in a Tree: C.O.D.I.N.G.

    View Slide

  2. •Community Engineer at Engine Yard
    •Author of Zend PHP 5 Certification
    Study Guide, Sitepoints PHP
    Anthology: 101 Essential Tips, Tricks
    & Hacks & PHP Master: Write
    Cutting Edge Code
    •A contributor to Zend Framework 1
    & 2, phpdocs, and PHP internals
    • @dshafik
    Davey Shafik

    View Slide

  3. BULLET
    • Bullet point

    • Bullet point

    • Bullet point
    BULLET
    • Bullet point

    • Bullet point

    • Bullet point
    BULLET
    • Bullet point

    • Bullet point

    • Bullet point
    BULLET
    • Bullet point

    • Bullet point

    • Bullet point
    About These Slides

    View Slide

  4. About These Slides
    • Two slides per “slide”
    • Title Slide (for when I’m talking)
    • Details slide (for later)
    • Nobody likes it when you can read the slide just as
    well as the speaker can
    • I like slides that are useful

    View Slide

  5. Why am I giving this talk?

    View Slide

  6. Why am I giving this talk?
    • Most Ruby developers I talk to are still writing PHP
    code on a regular basis.
    !
    • Full time PHP Developer, writing Ruby for Fun
    !
    • Freelance Ruby Developer, writing PHP for Clients
    !
    • Full time Ruby Developer, writing PHP for Fun
    !6

    View Slide

  7. They Think PHP Sucks

    View Slide

  8. Can’t we all just get along?

    View Slide

  9. PHP 5.3
    Release Date: June 30th 2009
    5-15% Faster

    View Slide

  10. Namespaces
    Better Code Organization

    View Slide

  11. Namespaces
    • Avoid Naming Collisions
    • Alias Long Names
    !11

    View Slide

  12. Namespaces
    • Namespace Defined at the top
    • Relative Namespaces are Supported
    • Import/Alias with "use" keyword
    !12
    namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>

    View Slide

  13. Namespaces
    !13
    namespace!Zend;!
    use!Zend\Http\Client\Adapter\Socket!as!HttpClient;!
    !!
    $client!=!new!Http\Client\Adapter\Socket;!
    $client!=!new!HttpClient;!
    $client!=!new!Zend\Http\Client\Adapter\Socket;!
    ?>

    View Slide

  14. PSR-0
    A new standard

    View Slide

  15. http://xkcd.com/927/

    View Slide

  16. PSR-0
    • Remove leading namespace separator
    • Replace namespace separator with directory separator
    • Replace underscores with directory separator
    • Add .php to the end
    !16

    View Slide

  17. PSR-0
    • Remove leading namespace separator
    • Replace namespace separator with directory separator
    • Replace underscores with directory separator
    • Add .php to the end
    !16
    '\Fully\Qualified\Class\Name'.gsub(/^\\+/,'')
    .gsub('\\', File::SEPARATOR)
    .gsub('_', File::SEPARATOR)

    + '.php'

    View Slide

  18. namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>
    PSR-0

    View Slide

  19. namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>
    PSR-0

    View Slide

  20. namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>
    PSR-0

    View Slide

  21. namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>
    PSR-0

    View Slide

  22. namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>
    PSR-0

    View Slide

  23. namespace Zend\Http\Client\Adapter;
    class Socket implements HttpAdapter, StreamInterface
    {
    }
    ?>
    PSR-0

    View Slide

  24. Composer
    getcomposer.org

    View Slide

  25. Bundler for PHP
    JSON instead of YAML

    View Slide

  26. Composer
    composer.json:!
    {!
    !!!!"require":!{!
    !!!!!!!!"monolog/monolog":!"1.2.*",!
    !!!!!!!!"phpunit/phpunit":!"3.*",!
    !!!!!!!!"zend/zendframework":!">=2.0,!!!!!!!!!"zend/zendframework":!"~2.0"!!!!!!!
    !!!!}!
    }

    View Slide

  27. Composer
    Install dependencies (from composer.lock)
    $ composer install
    !
    Update dependencies & write composer.lock
    $ composer update

    View Slide

  28. Autoloading
    require 'vendor/autoload.php';
    !
    use Zend\Http\Client\Adapter\Socket as HttpClient;
    $client = new HttpClient; 

    // Automagically (lazy) loaded
    !
    Optimize the Autoloader with a classmap:
    $ composer install --optimize-autoloader
    $ composer update --optimize-autoloader

    View Slide

  29. Closures
    (mostly)

    View Slide

  30. Closures
    $a = array(3, 2, 5, 6, 1);
    usort($a, function ($a, $b) {
    if ($a == $b) {
    return 0;
    }
    return ($a < $b) ? -1 : 1;
    });
    ?>

    View Slide

  31. PHP 5.4
    Release Date: March 1st 2012
    10-15% Faster (again)

    View Slide

  32. Short Echo Tags
    ="Now I Will Always Work!";?>

    View Slide

  33. Traits
    Horizontal Re-use
    Compile-Time Copy & Paste

    View Slide

  34. Traits
    trait getHello {
    public function hello() { return "Hello"; }
    }
    trait getWorld {
    public function world() { return "World"; }
    }
    trait sayHelloWorld {
    use getHello, getWorld;
    public function helloWorld() {
    echo $this->hello(), " ", $this->world();
    }
    }
    class Greeting {
    use sayHelloWorld;
    }
    (new Greeting)->helloWorld(); // Hello World

    View Slide

  35. Traits
    class!Greeting!{!
    !!!!use!sayHelloWorld!{!
    !!!!!!!!hello!as!private;!
    !!!!!!!!world!as!protected;!
    !!!}!
    }!
    !
    class!InformalGreeting!extends!Greeting!{!
    !!!!use!sayHelloWorld!{!
    !!!!!!!helloWorld!as:hiThere;!
    !!!}!
    }!
    !
    (new!InformalGreeting)=>hiThere();!//"Hello"World

    View Slide

  36. Closure Improvements

    View Slide

  37. Closure Improvements
    • Early binding on $this (now for the object in which it
    was created, instead of null)
    • Can change with $closure->bindTo()/
    Closure::bindTo()
    • Can set scope and $this to different things (watch
    out!)
    !32

    View Slide

  38. Callbacks

    View Slide

  39. Callbacks
    function invokeCallback(callable $var) {
    $var();
    }
    invokeCallback(function() { });
    invokeCallback("functionName");
    invokeCallback(['class', 'staticMethod']);
    invokeCallback([$object, 'method']);
    class Foo {
    public function __invoke() { }
    }
    invokeCallback(new Foo());

    View Slide

  40. Short Array Syntax
    ["foo",!"bar",!"baz"]!
    !!
    ["foo"!=>!"bar",!"baz"!=>!"bat"]

    View Slide

  41. Dereferencing

    View Slide

  42. Dereferencing
    function!bat()!{!
    !!!!return!["foo",!"bar"];!
    }!
    !!
    $foo!=!bat()[1];!//"bar!
    !
    PHP 5.5+
    !
    $foo!=!["foo",!"bar"][1];!//"bar!
    !
    $foo!=!"foo"[1];!//"o!
    !!
    function!baz()!{!
    !!!!return!"foo";!
    }!
    !!
    $foo!=!baz()[1];!//"o

    View Slide

  43. PHP 5.5
    Release Date: June 20th 2013

    View Slide

  44. Generators
    Simple Iterators

    View Slide

  45. Generators
    function gen() {
    echo 'start';
    yield 'middle';
    echo 'end';
    }
    // Initial call does not output anything, returns an instance of
    // the Generator class
    $gen = gen();
    // Call to current() resumes the generator, thus "start" is output.
    // Then the yield expression is hit and the string "middle" is
    // returned as the result of current() and then output.
    echo $gen->current();
    // Execution of the generator is resumed again, thus echoing "end"
    $gen->next();

    View Slide

  46. Generators
    function ifile($filename) {
    if (!$fh = fopen($filename, 'r')) {
    return;
    }
    while (($line = fgets($fh)) !== false) {
    yield $line;
    }
    fclose($fh);
    }
    // $lines is an instance of the Generator class
    $lines = ifile('/path/to/file');
    foreach ($lines as $line) {
    // do something with $line
    }

    View Slide

  47. Generators
    • Co-Routines: Send data in to generators with 

    ->send()

    • Send and Receive data at the same time

    • Send Exceptions into the Generator with 

    ->throw()
    !42

    View Slide

  48. Generators
    function!PasswordGenerator($min!=!1,!$max!=!null)!{:
    !!!!$chr!=!array_combine(range(32,!126),!array_map('chr',!range(32,!126)));!
    !!!!$ord!=!array_flip($chr);!
    !!!!$first!=!reset($chr);!
    !!!!$last!=!end($chr);!
    !!!!$length!=!$min;!
    !!!!$password!=!array_fill(0,!$length,!$first);!
    !!!!$stop!=!array_fill(0,!$length,!$last);!
    !!!!$end!=!$length!=!1;!
    !!!!while!($max!?!$max!>=!$length!:!true)!{!
    !!!!!!!!yield!implode('',!$password);!
    !!!!!!!!if!($password!==!$stop)!{!
    !!!!!!!!!!!!$length++;!
    !!!!!!!!!!!!$password!=!array_fill(0,!$length,!$first);!
    !!!!!!!!!!!!$stop!=!array_fill(0,!$length,!$last);!
    !!!!!!!!!!!!$end!=!$length!=!1;!
    !!!!!!!!}!else!{!
    !!!!!!!!!!!!for!($left!=!$end;!isset($password[$left])!
    ! ! ! !&&!$password[$left]!==!$last;!$left==);!
    !!!!!!!!!!!!if!(isset($password[$left])!&&!$password[$left]!!=!$last)!{!
    !!!!!!!!!!!!!!!!$password[$left]!=!$chr[$ord[$password[$left]]!+!1];!
    !!!!!!!!!!!!!!!!for!($index!=!$left!+!1;!$index!!!!!!!!!!!!!!!!!!!!!$password[$index]!=!$first;!
    !!!!!!!!!!!!!!!!}!
    !!!!!!!!!!!!}!
    !!!!!!!!}!
    !!!!}!
    }
    class!PasswordIterator!implements!Iterator!
    {!
    ! protected!$length;!
    ! protected!$min;!
    ! protected!$max;!
    ! protected!$counter;!
    ! protected!$password;!
    ! protected!$chr;!
    ! protected!$ord;!
    ! protected!$first;!
    ! protected!$last;!
    ! protected!$end;!
    ! protected!$stop;!
    ! public!function!__construct($min!=!1,!$max!=!null)!{:
    ! ! $this=>min!=!$min;!
    ! ! $this=>max!=!$max;!
    ! ! $this=>chr!=!array_combine(range(32,!126),!array_map('chr',!range(32,!126)));!
    ! ! $this=>ord!=!array_flip($this=>chr);!
    ! ! $this=>first!=!reset($this=>chr);!
    ! ! $this=>last!=!end($this=>chr);!
    ! ! $this=>rewind();!
    ! }!
    ! protected!function!increment()!{:
    ! ! $this=>length++;!
    ! ! $this=>password!=!array_fill(0,!$this=>length,!$this=>first);!
    ! ! $this=>stop!=!array_fill(0,!$this=>length,!$this=>last);!
    ! ! $this=>end!=!$this=>length!=!1;!
    ! }!
    ! public!function!rewind()!{:
    ! ! $this=>length!=!$this=>min!=!1;!
    ! ! $this=>counter!=!1;!
    ! ! $this=>increment();!
    ! }!
    ! public!function!current()!{:
    ! ! return!implode('',!$this=>password);!
    ! }!
    ! public!function!key()!{:
    ! ! return!$this=>counter;!
    ! }!
    ! public!function!next()!{:
    ! ! $this=>counter++;!
    ! ! if!($this=>password!==!$this=>stop)!{!
    ! ! ! $this=>increment();!
    ! ! }!else!{!
    ! ! ! for!($left!=!$this=>end;!isset($this=>password[$left])!!
    ! ! ! ! &&!$this=>password[$left]!==!$this=>last;!$left==);!
    ! ! ! if!(isset($this=>password[$left])!&&!$this=>password[$left]!!=!$this=>last)!{!
    ! ! ! ! $this=>password[$left]!=!$this=>chr[$this=>ord[$this=>password[$left]]!+!1];!
    ! ! ! ! for!($index!=!$left!+!1;!$index!length;!$index++)!{!
    ! ! ! ! ! $this=>password[$index]!=!$this=>first;!
    ! ! ! ! }!
    ! ! ! }!
    ! ! }!
    ! }!
    ! public!function!valid()!{:
    ! ! return!$this=>max!?!($this=>max!>=!$this=>length)!:!true;!
    ! }!
    }
    Generator Iterator

    View Slide

  49. finally
    (finally!)

    View Slide

  50. “finally” keyword
    !45
    • Code within a finally block always is run after
    either of the try, or catch blocks.
    try {
    // Try something
    } catch (\Exception $exception) {
    // Handle exception
    } finally {
    // Whatever happened, do this
    }

    View Slide

  51. Behat
    Cucumber for PHP
    behat.org

    View Slide

  52. Behat: Gherkin Syntax
    Feature: Multiple site support
    Background:
    Given a global administrator named "Greg"
    And a blog named "Greg's anti-tax rants"
    And a customer named "Wilson"
    And a blog named "Expensive Therapy" owned by "Wilson"
    Scenario: Wilson posts to his own blog
    Given I am logged in as Wilson
    When I try to post to "Expensive Therapy"
    Then I should see "Your article was published."
    Scenario: Greg posts to a client's blog
    Given I am logged in as Greg
    When I try to post to "Expensive Therapy"
    Then I should see "Your article was published."

    View Slide

  53. Mink
    Behat Plugin for Headless Browser Support

    View Slide

  54. Behat: Mink
    • Goutte (PHP-based)
    • Sahi
    • Zombie.js
    • Selenium/Selenium 2
    !49

    View Slide

  55. CodeCeption
    Acceptance + Functional + Unit Testing
    codeception.com

    View Slide

  56. Codeception
    • Selenium 2 or PhpBrowser for Acceptance Testing
    • Built-in framework support for Functional Testing
    (e.g. Symfony, Zend Framework 2)
    • Extends standard PHPUnit tests for Unit Testing
    !51

    View Slide

  57. ReactPHP
    Asynchronous Event-based Applications
    reactphp.org

    View Slide

  58. ReactPHP
    $app = function ($request, $response) {
    $response->writeHead(200,['Content-Type' => ‘text/plain']);
    $response->end("Hello World\n");
    };
    $loop = React\EventLoop\Factory::create();
    $socket = new React\Socket\Server($loop);
    $http = new React\Http\Server($socket, $loop);
    $http->on('request', $app);
    echo "Server running at http://127.0.0.1:8080\n";
    $socket->listen(8080);
    $loop->run();
    Uses LibEV, LibEvent or Streams Socket Select

    View Slide

  59. ReactPHP
    !
    • Async Redis Client
    • ZeroMQ, Stomp Support
    • Promises (CommonJS Promises/A)
    • Partials
    • GifSocket

    "Real Time communication library using Animated
    Gifs as a transport™" - Alvaro Videla.
    !54

    View Slide

  60. Party Like It’s 1999
    9
    Goto

    View Slide

  61. Party Like It’s 1999
    5
    Goto

    View Slide

  62. Obligatory XKCD

    View Slide

  63. Goto
    __label__(:loop)
    puts "Woooooooo"
    __goto__(:loop)
    puts "This line of code is never reached."
    Yes, that’s Ruby! Just compile with SUPPORT_JOKE!
    http://ey.io/ruby-goto

    View Slide

  64. Goto
    loop:
    echo "Woooooo";
    goto loop;
    echo "This line of code is never reached.";

    View Slide

  65. Goto
    • Must be within the same file & context
    • Cannot jump into or out of a function
    • Cannot jump into a loop, or switch
    • You can jump out of a loop/switch
    !59

    View Slide

  66. Thank You
    Feedback:
    Twitter: @dshafik
    Email: [email protected]
    !
    Slides:
    http://daveyshafik.com/slides

    View Slide