Alright, now we’re getting into some real differences between Ruby and PHP.

PHP’s Take on Setters & Getters (the Classical OOP Method)

If you’ve ever the pleasure of using Symfony’s Doctrine as an ORM, you’ll be super familiar with the concept of setters & getters. The origin of this pattern goes way back to the Java days.

The idea is that the underlying property of an object is accessible, but the method to set a new value is controlled.

Let’s start with a contrived example:

/**
 * A contrived User class
 *
 * @author Dylan Pierce <me@dylanjpierce.com>
 */
class User {
  
  /**
   * @var string
   */
  private $first_name = 'Dylan';

  /**
   * First Name Getter
   *
   * @return string
   */
  public function getFirstName() {
    return $this->first_name; 
  }
}

Now we can instantiate a new User and get their first name:

$user = new User;
echo $user->getFirstName();

=> 'Dylan'

Now let’s add a Setter so that we can actually change the user’s name at runtime:

/**
 * A contrived User class
 *
 * @author Dylan Pierce <me@dylanjpierce.com>
 */
class User {
  
  /**
   * @var string
   */
  private $first_name = 'Dylan';

  /**
   * First Name Getter
   *
   * @return string
   */
  public function getFirstName() {
    return $this->first_name; 
  }

  /**
   * First Name Setter
   *
   * @param string
   * @return void
   */
  public function setFirstName($firstName) {
    $this->first_name = $firstName;
  }
}

Woo! Now we can set the User’s first name during registration:

$user = new User;
$user->setFirstName('Amy');

echo $user->getFirstName();

=> 'Amy'

Now you’re probably wondering, why don’t we just make the User->first_name property public? That way we can set it with $user->first_name = 'Amy' and skip all of that Setter/Getter nonsense.

Well you could do it that way, but let’s say we need to perform a transformation on that data. For example, what happens if our user makes a mistake and forgets to capatilize their own name during registration?

$user = new User;
$user->setFirstName('amy');

echo $user->getFirstName();

=> 'amy'

Uh oh. Now throughout our application we’ll call our awesome user amy instead of Amy.

Here’s where a setter can save us:

/**
 * A contrived User class
 *
 * @author Dylan Pierce <me@dylanjpierce.com>
 */
class User {
  
  /**
   * @var string
   */
  private $first_name = 'Dylan';

  /**
   * First Name Getter
   *
   * @return string
   */
  public function getFirstName() {
    return $this->first_name; 
  }

  /**
   * First Name Setter
   *
   * @param string
   * @return void
   */
  public function setFirstName($firstName) {
    $this->first_name = ucfirst($firstName);
  }
}

We’ve added the ucfirst($string) function to our setFirstName method. That way all input is transformed to have the first word to be capatialized. In this case from amy to Amy automagically:

$user = new User;
$user->setFirstName('amy');

echo $user->getFirstName();

=> 'Amy'

Those familiar with Laravel’s Eloquent ORM will be scratching their heads at this example. Under the hood Eloquent is doing something similar by storing the model’s data as an array under $_attributes and using some clever PHP magic methods to check for specially named setter methods.

It’s a little complex to show here. The classic Getter/Setter method is much easier to understand.

Ruby’s Setters/Getters

You may have noticed to get that functionality we had to do quite a bit of typing. That’s normal for statically defined languages like PHP and Java. It’s verbose and kind of ceremonious.

Ruby offers a special shortcut to create setters and getters for your classes. Let’s start with the way we’d normally create a new class based on what we know about static languages:


# A contrived User example
#
# @author Dylan Pierce <me@dylanjpierce.com>
class User
  @first_name = 'Dylan'

  def first_name
    return @first_name
  end
end

A couple of questions you might have right off the bat:

What the heck is this @ character doing in the variable @first_name?

In Ruby, we have different levels of variables. The @ denotes that the variable is a class variable. A class variable is just a variable that is available anywhere within the class.

You can think of $this->first_name and @first_name as being logically equivalent. Both are variables that have special context in that they’re “shared” across all methods in the class.

Next question you might have is where’s the keyword get in the getter method? Shouldn’t it be something like get_first_name?

You could name your getter method that way, but you’ll come to see soon that there’s a reason for this.

Regardless if you have a solid grasp on these differences, let’s continue by actually using this new User class:


user = User.new

puts user.first_name

=> 'Dylan'

Now, let’s craft a Setter method by hand in our User Ruby Class:


# A contrived User example
#
# @author Dylan Pierce <me@dylanjpierce.com>
class User
  @first_name = 'Dylan'

  def first_name=(first_name)
    @first_name = first_name
  end

  def first_name
    return @first_name
  end
end

Yup, you’re seeing that right. There’s a big ole = right in the method name. Alongside of the fact it accepts an argument, it’s exactly the same name as our getter.

It’s threw me for a tiff for a long time. Don’t expect it to be or feel natural at first. But here’s the class in use just like we did in the PHP implementation:


user = User.new

user.first_name('Amy')
puts user.first_name

=> 'Amy'

Using Ruby Shorthand to Generate Setters and Getters

Now manually typing getters and setters for Ruby’s classes are lot less legwork (or should I say fingerwork) typing than it’s PHP cousin. But we have another special treat that’s built into the Ruby language.

It’s natural for Ruby to have shortcuts for building out OOP functionality since everything is an object.

Ruby offers 3 more specialized keywords in classes to generate getters, setters or both at the same time.

Let’s generate the setters and getters seperately. Now this will be logically equivalent to our User class in former examples:


class User
  attr_reader :first_name
  attr_writer :first_name
end

So as you can probably guess, attr_reader are our reading methods (a.k.a. getter methods). attr_writer are our writing methods (a.k.a. setter).


user = User.new

user.first_name('Amy')
puts user.first_name

=> 'Amy'

But wait there’s more.

Not only do you have the shortcut methods of attr_reader and attr_writer but you have a third method that covers both: attr_accessor.

This means we can reduce our User class to 3 lines of code:


class User
  attr_accessor :first_name
end

This will give us the same exactly functionality, but with a huge cost savings in terms of typing. Reducing this type of boilerplate is huge for your productivity and ultimately let’s you solve problems rather that typing or relying on a heavy IDE to constantly create boilerplate code.