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

Notes from a PHP Immigrant

Notes from a PHP Immigrant

While PHP (in its object-oriented form) and Ruby are similar in their overall strategy to solving problems, they have a number of key differences. Some of them are obvious and dramatic, while others are more subtle. In this talk, I cover how Ruby forced me to adjust my approach to writing software, and how it enabled me to better express my existing thoughts about code design.

Yitz Schaffer

May 12, 2015
Tweet

More Decks by Yitz Schaffer

Other Decks in Technology

Transcript

  1. PHP and Ruby def sum(a, b) a + b end

    function sum($a, $b) { return $a + $b; }
  2. PHP and Ruby some_values = [ :foo, :bar, :baz ]

    $someValues = [ 'foo', 'bar', 'baz' ];
  3. PHP and Ruby module Foo class Adder < MathOperation def

    initialize(initial_value) @initial_value = initial_value end def add_one @initial_value + 1 end end end Foo::Adder.new(4).add_one => 5 namespace Foo class Adder extends MathOperation { private $initialValue; public function __construct($initialValue) { $this->initialValue = $initialValue; } public function addOne() { return $this->initialValue + 1; } } (new \Foo\Adder(4))->addOne() => 5
  4. PHP and Ruby [1, 2, 3].map { |x| x +

    1 } array_map(function($x) { return $x + 1; }, [1, 2, 3]);
  5. PHP: lots of things are not objects Ruby: everything is

    an object (?) 1 3.45 'abc' [$something] function bar() {} class Foo {} mysql_connect()
  6. abstract class Renderer { public function render(Tweet $tweet); } class

    AbstractRenderer def render(tweet) fail NotImplementedError end end Types!
  7. irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=,

    :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, Broad base of built-in methods
  8. irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=,

    :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, : slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :| Broad base of built-in methods
  9. irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=,

    :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, : slice, :slice!, :assoc, :rassoc, : +, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :s huffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch Broad base of built-in methods
  10. irb(main):004:0> Array.instance_methods - Object.instance_methods => [:to_a, :to_ary, :[], : []=,

    :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rind ex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, : slice, :slice!, :assoc, :rassoc, : +, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :s huffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch, :pa ck, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :min max, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slic e, :each_cons, :each_with_object, :chunk, :slice_before, :lazy] Broad base of built-in methods
  11. function blow_it_up($data) { $data['foo'] = 'BOOM'; return $data; } $a

    = ['foo' => 'bar']; $b = blow_it_up($a); $a['foo'] // 'bar' PHP: pass-by-copy for non-objects
  12. def blow_it_up(data) data[:foo] = 'BOOM' data end a = {foo:

    'bar'} b = blow_it_up(a) a[:foo] => 'BOOM' Ruby: regular ol' pass-by-value
  13. def blow_it_up(data) data[:foo] = 'BOOM' data end a = {foo:

    'bar'} b = blow_it_up(a) a[:foo] => 'BOOM' Ruby: regular ol' pass-by-value
  14. [ 'baz', 'quux' ] { foo: 'bar' } Lists and

    Maps: Array, Hash, array()
  15. array( 0 => 1, 1 => 2, 2 => 3,

    3 => 4, 4 => 5 ) Filtering Lists
  16. array( 0 => 1, 1 => 2, 2 => 3,

    3 => 4, 4 => 5 ) Filtering “Lists” i.e. Hashes
  17. array( 0 => 1, 1 => 2, 2 => 3,

    3 => 4, 4 => 5 ) apply filter… function($x) { return $x % 2 == 0; } Filtering “Lists” i.e. Hashes
  18. array( // 0 => 1, 1 => 2, // 2

    => 3, 3 => 4, // 4 => 5 ) apply filter… Filtering “Lists” i.e. Hashes function($x) { return $x % 2 == 0; }
  19. array( 1 => 2, 3 => 4 ) apply filter…

    Filtering “Lists” i.e. Hashes
  20. array( 1 => 2, 3 => 4 )[0] PHP Notice:

    Undefined offset: 0 Filtering “Lists” i.e. Hashes
  21. array( 1 => 2, 3 => 4 )[0] PHP Notice:

    Undefined offset: 0 Filtering “Lists” i.e. Hashes array_values(array( 1 => 2, 3 => 4 ))[0] => 2
  22. class Person { public function renderSalutation() { $fullName = '';

    $fullName .= $this->firstName(); $fullName .= ' '; $fullName .= $this->lastName(); return $fullName . ', ' . $this->renderTitle(); } } Variable and Method Names
  23. class Person { public function renderSalutation() { // extracted method

    from up here return $fullName . ', ' . $this->renderTitle(); } public function fullName() { $fullName = ''; $fullName .= $this->firstName(); $fullName .= ' '; $fullName .= $this->lastName(); return $fullName; } } Variable and Method Names
  24. class Person { public function renderSalutation() { return $this->fullName() .

    ', ' . $this->renderTitle(); } public function fullName() { $fullName = ''; $fullName .= $this->firstName(); $fullName .= ' '; $fullName .= $this->lastName(); return $fullName; } } Variable and Method Names
  25. class Person def renderSalutation full_name = '' full_name += full_name

    + first_name full_name += ' '; full_name += last_name full_name + ', ' + renderTitle end end Variable and Method Names
  26. class Person def renderSalutation full_name + ', ' + renderTitle

    end def full_name full_name = '' full_name += full_name + first_name full_name += ' '; full_name += last_name end end Variable and Method Names
  27. > Array(nil) => [] > Array([]) => [] > Array('foo')

    => ['foo'] > Array(['foo']) => ['foo'] Data Type Coercion
  28. vowel = Proc.new do |x| ['a', 'e', 'i', 'o', 'u'].include?(x.downcase)

    end 'what is my first vowel?'.split('').find { |letter| vowel.call(letter) } => 'a' Higher-order syntax sugar
  29. vowel = Proc.new do |x| ['a', 'e', 'i', 'o', 'u'].include?(x.downcase)

    end 'what is my first vowel?'.split('').find { |letter| vowel.call(letter) } 'what is my first vowel?'.split('').find(&vowel) => 'a' Higher-order syntax sugar
  30. > ['foo', 'bar'].map(&:reverse) => ["oof", "rab"] Higher-order syntax sugar >

    p = :reverse.to_proc => #<Proc:0x007fb4411bfec0> > p.call('jim') => "mij"
  31. > { Date.new => [1,2,3] } => { #<Date:0x007fc8609c6a78> =>

    [1,2,3] } Arbitrary Object as Hash key
  32. class Whatever def initialize @state = SomeState.new end def foogle

    with_alternate_state do calculated_value end end def with_alternate_state original_state = @state.dup @state.mutate! yield @state = original_state end end Block as state sandbox (evil)