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. •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
  2. 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
  3. 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
  4. 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
  5. Namespaces • Namespace Defined at the top • Relative Namespaces

    are Supported • Import/Alias with "use" keyword !12 <?php namespace Zend\Http\Client\Adapter; class Socket implements HttpAdapter, StreamInterface { } ?>
  6. PSR-0 • Remove leading namespace separator • Replace namespace separator

    with directory separator • Replace underscores with directory separator • Add .php to the end !16
  7. 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'
  8. Composer Install dependencies (from composer.lock) $ composer install ! Update

    dependencies & write composer.lock $ composer update
  9. Autoloading <?php 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
  10. Closures <?php $a = array(3, 2, 5, 6, 1); usort($a,

    function ($a, $b) { if ($a == $b) { return 0; } return ($a < $b) ? -1 : 1; }); ?>
  11. 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
  12. 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
  13. Callbacks function invokeCallback(callable $var) { $var(); } invokeCallback(function() { });

    invokeCallback("functionName"); invokeCallback(['class', 'staticMethod']); invokeCallback([$object, 'method']); class Foo { public function __invoke() { } } invokeCallback(new Foo());
  14. 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
  15. 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();
  16. 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 }
  17. 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
  18. 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!<!$length;!$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!<!$this=>length;!$index++)!{! ! ! ! ! ! $this=>password[$index]!=!$this=>first;! ! ! ! ! }! ! ! ! }! ! ! }! ! }! ! public!function!valid()!{: ! ! return!$this=>max!?!($this=>max!>=!$this=>length)!:!true;! ! }! } Generator Iterator
  19. “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 }
  20. 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."
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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