Confessions of a Converted PHP Developer: On Visibility and Privates

Alright class—today I’m here to talk about the differences and similarities that PHP and Ruby have when it comes to object properties, methods, and their visibility—how you create variables inside classes, and how you can interact with them.

A Quick Recap of What We Know

In PHP, an object’s properties can be set to one of three visibilities; public, protected, and private. Properties that don’t have a visibility declaration default to public. Each of these declarations change what information is available to the class itself, its parents and children objects, and other code interacting with it. Let’s recap on how they work quickly.

  • Public variables are available everywhere
  • Protected variables are available only inside the class and its parents or children
  • Private variables are only available in the class where they are specified, and are not available to classes that extend it

To handle interactions with protected and private properties it’s common to create getter and setter accessor methods. These are functions that allow you to set and retrieve the values of properties, and generally all look pretty similar—unless they’re actually doing manipulation to the data that’s stored, it’s common to see them as just single line functions returning or setting the property:

<?PHP
&nbsp;
class animal
{
  private $_species;
  protected $_name;
&nbsp;
  public function get_species()
  {
    return $this->_species;
  }
&nbsp;
  public function get_name()
  {
    return $this->_name;
  }
}
&nbsp;
class pterodactyl
  extends animal
{
  public function __construct()
  {
    $this->_name = $name;
    $this->_species = 'dinosaur';
  }
}
&nbsp;
$my_big_birdie = new pterodactyl('Daryl');
&nbsp;
var_dump($my_big_birdie->get_name()); // string(5) 'Daryl'
var_dump($my_big_birdie->get_species()); // NULL

Calling the get_name method returns the name we set, since that variable was protected and available in the child class. By setting _species in the child class, it created a new public property called _species, and left the private _species property in the parent class NULL. A full dump of $my_big_birdie will show us this:

Object(pterodactyl)#1 (3) {
  ["_species":"animal":private]=> NULL
  ["_name":protected]=> string(5) "Daryl"
  ["_species"]=> string(8) "dinosaur"
}

Ruby doesn’t exactly have properties as we think of them. Instead you have to define getter and setter methods for any instance variables you want to access. These are commonly referred to as readers and writers. (Variables with an @ symbol in front of them are instance variables, which means that they’re available inside the scope of the class.)

class Animal
  def initialize(name)
    @name = name
  end
&nbsp;
  def name
    @name
  end
&nbsp;
  def name=(name)
    @name = name
  end
&nbsp;
  def species
    @species
  end
end

In this example we’ve implemented the animal class from PHP into Ruby. Note how the setter is defined by simply adding an equals to the end of the method name.

Since writing getters and setters can be a repetitive process, Ruby simplifies this by enabling us to declare which instance variables we want available as attributes:

class Animal
  attr_reader :species
  attr_accessor :name
&nbsp;
  def initialize(name)
    @name = name
  end
end

We now have the same class as before, except we’re creating our getters and setter with the Ruby attr_reader and attr_accessor. attr_reader creates only a getter method, attr_writer (unused here) only a setter method and attr_accessor creates both methods. 90% of the time this is all we need to do to expose our variables as attributes and for those times where you need more functionality, you can simply use the standard method construct.

Ruby also has a different implementation of Public, Private and Protected. By default all methods are public, but you can declare visibility by making a single protected or private statement and then any methods that follow will have that visibility. This allows you to group together methods with the same visibility:

class MyClass
  # the default visibility is public
  def my_public_method
  end
&nbsp;
  protected
  def my_protected_method
  end
&nbsp;
  def my_other_protected_method
  end
&nbsp;
  private
  def my_private_method
  end
end

Ruby’s implementation of protected and private is very different to PHP’s and has nothing at all to do with object inheritance. Private in Ruby is more akin to Protected in PHP. A private method in Ruby can be accessed inside the context of an object, or any inherited object.

class Foo
  private
  def bar
    puts "bar called"
  end
end
&nbsp;
class Blarg < Foo
  def initialize
    bar
  end
end

Because Blarg class extends Foo, it’s able to call the private method bar.

The implementation of protected in Ruby is different entirely to anything in PHP. Protected methods can be called by any object of the same class:

class Person
  attr_writer :mother
&nbsp;
  def initialize(name)
    @name = name
  end
&nbsp;
  def mother_name
    @mother.name if 
  end
&nbsp;
  protected
  def name
    @name
  end
end
&nbsp;
me = Person.new('Mal')
mum = Person.new('Jeni')
&nbsp;
me.mother = mum
&nbsp;
puts me.mother_name # => Jeni
puts me.name        # => NoMethodError: protected method `name' called for #

Here we have a person class that allows protected access to the name only. When I create two instances and set the mother attribute of one instance to the other instance, then the mother_name method is capable of calling the mother variable’s name attribute, however I’m not capable of calling the name attribute outside the scope of the object itself.

This was a brief overview of some of the fundamental differences between PHP and Ruby’s class properties and method visibility—can you think of any other core differences that are worth mentioning?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://blog.jorygeerts.nl Jory Geerts

    Nice article. I’m pretty new to Ruby (and haven’t touched Rails) and articles like this make it much easier to see the differences.

    One small note: “The implementation of protected in Ruby is different entirely to anything in PHP. Protected methods can be called by any object of the same class”
    Thats not actually true – in PHP, instances of the same class can interact with eachothers protected and even private properties.

  • http://avalanche123.com Bulat Shakirzyanov

    Private members (attributes and methods) in PHP work the same way as protected in Ruby – e.g. they are available inside class, even if you access member of a different instance of the same class:

    name = $name;
    }

    public function setMother(Person $mother)
    {
    $this->mother = $mother;
    }

    public function getMotherName()
    {
    if (isset($this->mother)) {
    return $this->mother->name;
    }
    }
    }

    $me = new Person(‘Mal’);
    $mum = new Person(‘Jeni’);

    $me->setMother($mum);

    echo $me->getMotherName();

    Cheers!

  • http://paul.annesley.cc/ Paul Annesley

    Methods created by attr_reader, attr_writer and attr_accessor are also subject to visibility:


    ruby-1.9.2-p180 :001 > Class.new{ private; attr_accessor :a }.new.a
    NoMethodError: private method `a' called for #<#:…>

  • rsludge

    Thanks for this article, I never used ‘protected’ in Ruby but it seems to be very helpful to hide methods, that I don’t want to be used outside the class scope.

  • Petah

    Man, Ruby syntax is ulgy!

    • http://mal.co.nz Mal Curtis

      Really ulgy ;)

  • http://www.phpadvocate.com Jonathon Hibbard

    Jory:
    I’m sorry, that is completely wrong. Private methods/properties can only be accessed by the class that has defined them. Classes that extend a parent class can only access the parent’s methods/variables if they are protected or public.

    Example:
    class a {
    private $var1 = ‘test’;
    protected $var2 = ‘test’;
    public $var3 = ‘test’;

    private function classA_private_method() {
    echo “called!”;
    }

    protected function classA_protected_method() {
    echo “called!”;
    }

    public function classA_public_method() {
    echo “Called!”;
    }
    }

    class b extends a {
    private $var4 = ‘test’;
    protected $var5 = ‘test’;
    public $var6 = ‘test’;

    public function __construct() {
    echo parent::$var1;
    echo parent::$var2;
    echo parent::$var3;

    parent::classA_private_method();
    parent::classA_protected_method();
    parent::classA_public_method();
    }
    }

    $b = new b();

    In the above example, calls to private_method or $var1 will result in fatal errors, as the “b” class does NOT have access to these properties/methods.

    • http://mal.co.nz Mal Curtis

      Hey Jonathan,

      I think he was referring to the fact that an instance of class a, can access protected / private properties of ANOTHER instance of class a (the same class).

      • http://www.phpadvocate.com Jonathon Hibbard

        Mal: even that is incorrect. Each time a new instance is created, a new object is created. That means that each object can have the same property names, but have completely different values.

        Even if you pass the new instance of class a (the same class) to the class a object, it cannot access the new instance properties (as they are defined private). All because they have the same name and object type doesn’t mean anything. At the end of the day, they would be treated as 2 separate objects and thus the access permissions apply.

        protected methods/properties go without saying: you can access these methods/properties if you are extending then through inheritance only (so only subclasses can access protected methods (or the parent itself)).

        • http://mal.co.nz Mal Curtis

          Sorry Jonathan, you’re wrong. Your note about each instance having its own values is correct, but their visibility is not as your describe.

          <?PHP

          class foo{
          protected $protected = "I'm protectedn";
          private $private = "I'm privaten";

          public function test($obj)
          {
          echo $obj->protected;
          echo $obj->private;
          }
          }

          class bar extends foo{
          public function test($obj)
          {
          echo $obj->protected;
          echo $obj->private;
          }

          }

          $a = new foo;
          $b = new foo;
          $c = new bar;

          $a->test($b);
          $c->test($b);

          Outputs:
          I’m protected
          I’m private
          I’m protected
          PHP Fatal error: Cannot access private property foo::$private in /home/mal/scripts/test.php on line 19

          So one instance can access the private and protected properties of another instance, but obviously when it’s extended it can’t access the private property, only the protected one.

  • Jonathon Hibbard

    Mal,
    You are absolutely correct and I was very much wrong. Next time I’ll test my theory out before stating it as fact haha

    A year late, but better late than never ;)

    -Jon