PHP OOP Class Encapsulation (Access Modifiers) Tutorial

In this tutorial we learn how to restrict internal access to our classes with the private, protected and public access modifiers.

We also cover getters and setters, and the abstract and final access modifiers.

What is encapsulation?

Encapsulation allows us to hide attributes and methods inside a class so that other classes won’t have access to them. As an example, let’s consider a class that translates a document into another language.

The class would contain all the methods and attributes needed for loading, manipulating and closing a file. We don’t need to worry about the specifics of what it does behind the scenes. All we need to do is instantiate the class and send it the appropriate commands, like: open a file from this location, save a file to that location etc.

Encapsulation also provides us with data protection. We can’t accidentally change how a file is manipulated from outside the class if it’s properly protected.

Class encapsulation with access modifiers

To encapsulate members of our class, we need to use certain access modifiers. These are keywords that specify the level of access, or protection, class members have.

The table below shows the available access modifiers:

ModifierMeaning
publicNo access restriction. Can be accessed from anywhere, even from outside of the class scope.
privateCan only be accessed from within the class that defines it.
protectedCan only be accessed from within the class that defines it as well as any child class.
abstractIndicates that a class or a method is missing its implementation.
finalMethods defined as final, cannot be changed or overridden by a subclass.

How to use the public access modifier

By default, when we don’t explicitly state which access modifier to use, all members of a class are public.

The public access modifier cannot be used on the class itself and must instead be used on its attributes or methods. To state that a member is public, we simply write the keyword public in front of the member’s definition statement.

Syntax:
class ClassName {

    public $variableName;

    public function methodName() {

    }
}

In the case of an attribute, the access modifier keyword replaces the var keyword.

Example: public access modifier
<?php

class Car {

    public $topSpeed;

    function __construct($topSpeed) {
        $this->topSpeed = $topSpeed;
    }

    public function drive() {
        return "Driving at " . $this->topSpeed . " vrooms";
    }
}

$car1 = new Car(120);
echo "Top speed for this car is " . $car1->topSpeed;

?>

In the example above we can access the $topSpeed attribute directly through the object because it’s access level is set to public.

How to use the private access modifier

When we specify that a member should be private , it means that it can only be used inside the class. It will not be available to use through the object.

Syntax:
class ClassName {

    private $variableName;

    private function methodName() {

    }
}
Example: private access modifier
<?php

class Car {

    private $topSpeed;

    function __construct($topSpeed) {
        $this->topSpeed = $topSpeed;
    }

    public function drive() {
        return "Driving at " . $this->topSpeed . " vrooms<br>";
    }
}

$car1 = new Car(120);
echo $car1->drive();

// will raise an error if we try to access a private member
echo "Top speed for this car is " . $car1->topSpeed;

?>

In the example above we are allowed to use the $topSpeed attribute inside the class in a method like drive(). Because the drive() method is public, we can access it through the object instance.

If we try to access the private attribute directly, the interpreter will raise an error.

Output:
 Fatal error: Uncaught Error: Cannot access private property Car::$topSpeed

How to use the protected access modifier

The protected access modifier is the same as the private modifier except that the member will be available to any child class that inherits from this class.

Syntax:
class ClassName {

    protected $variableName;

    protected function methodName() {

    }
}
Example: protected access modifier
<?php

class ParentClass {

    protected $parentMsg = "protected parent attribute<br>";

    protected function parentDisplay() {
        echo "protected parent method<br>";
        echo $this->parentMsg;
    }
}

class ChildClass extends ParentClass {

    protected $childMsg = "Protected Child attribute.<br>";

    public function childDisplay() {
        echo "Public Child method to display protected parent members:<br>";
        $this->parentDisplay();
    }

}

$parent = new ParentClass();
$parent->parentDisplay();

?>

In the example above, our ParentClass has both of its members marked as protected. Similar to the private modifier, when we try to access the protected members, the interpreter raises an error.

Output:
 Fatal error: Uncaught Error: Call to protected method ParentClass::parentDisplay()

We are allowed to access the protected ParentClass members inside the ChildClass.

Example:
<?php

class ParentClass {

    protected $parentMsg = "protected parent attribute<br>";

    protected function parentDisplay() {
        echo "protected parent method<br>";
        echo $this->parentMsg;
    }
}

class ChildClass extends ParentClass {

    protected $childMsg = "Protected Child attribute.<br>";

    public function childDisplay() {
        echo "Public Child method to display protected parent members:<br>";
        $this->parentDisplay();
    }

}

$child = new ChildClass();
$child->childDisplay();

?>

In the example above, our childDisplay() method uses the protected method from the ParentClass. The childDisplay() method can print the text because it has the public access modifier applied.

Accessor and mutator methods (getters & setters)

Accessor and mutator methods are ways for us to interact with the private and protected members of a class. They are also referred to as getters and setters.

These methods are public methods that get or set the values of private attributes.

Syntax:
private $attribute;

public function getAttribute()
{
    return $this->attribute;
}

public function setAttribute($parameter)
{
    $this->attribute = $parameter;
}
Example: getters and setters
<?php

class Car {
    private $topSpeed = 100;

    public function getTopSpeed() {
        return $this->topSpeed;
    }

    public function setTopSpeed($newTopSpeed) {
        $this->topSpeed = $newTopSpeed;
    }
}

$car1 = new Car();

echo "Top speed: " . $car1->getTopSpeed();

$car1->setTopSpeed(140);

echo "<br>New top speed: " . $car1->getTopSpeed();

?>

In the example above, our $topSpeed attribute is marked as private but we can get or set it’s value through the public accessor and mutator methods.

How to use the abstract access modifier

The abstract modifier indicates that a class member is missing its implementation. This is similar to an interface, which we look at in the Interfaces section.

Syntax:
abstract class ParentClass {

    abstract modifier function methodName();

}

class ChildClass extends ParentClass {

    modifier function methodName() {
        // method implementation
    }

}

The method marked as abstract must be overridden in any inheriting class and provide its own implementation.

Example: abstract access modifier
<?php

abstract class Car {

    abstract public function drive();
}

class Coupe extends Car {

    public function drive() {
        return "Driving fast";
    }

}

$car1 = new Coupe();
echo $car1->drive();

?>

In the example above, the drive() method in the Car class is defined without a body, it has no implementation.

The Coupe child class has to override the drive() method and provide its own implementation. To keep things simple, the implementation is just a text string.

Because abstract classes are so strict, we can provide common behavior while still forcing other developers to follow our design.

In the example above, we force a developer to provide a drive() method for whichever type of car they are designing.

There are a few rules that we should keep in mind when working with abstract classes.

  • An abstract class cannot be instantiated, we can't create an object from it. We need a child class that extends it, then we can create an object of the child class.
  • If a class contains one or more abstract methods, the class itself must be abstract as well.
  • An abstract method is a declaration only, it does not have a body. Because of this, the declaration statement is terminated with a semicolon.

Abstract classes may contain both regular and abstract methods.

Example:
<?php

abstract class Car {

    private $topSpeed = 160;

    // Regular method
    public function drivingSpeed() {
        return "Driving at " . $this->topSpeed . " km/h<br>";
    }

    // Abstract method
    abstract public function drive();
}

class Coupe extends Car {

    public function drive() {
        return "Driving fast";
    }

}

$car1 = new Coupe();
echo $car1->drivingSpeed();

?>

In the example above, our Car class contains a regular method as well as an abstract method.

Because the whole class is abstract, and abstract classes may not be instantiated, we still have to access the regular method through a child class.

How to use the final access modifier

The final access modifier can be used in two ways, for methods and classes, and behaves differently when applied to each.

  • When applied to a class, it prevents inheritance from any other class.
  • When applied to a method, it prevents the method from being overridden.

final access modifier on a class

A developer might decide that they do not want a class to be inherited. To block a class from being inherited, we use the final keyword on the class definition itself.

Syntax:
final class Parent {

}
Example: final class
<?php

final class ParentClass {}

class ChildClass extends ParentClass {}

?>

In the example above, we mark the ParentClass definition with the keyword final , indicating that we don’t want any other class to inherit from it.

When we try to inherit from ParentClass, the interpreter raises an error.

Output:
 Fatal error: Class ChildClass may not inherit from final class (ParentClass)

A final class may contain both final and non-final methods.

Example:
<?php

final class ParentClass {

    final function message1() {
        echo "A final class may contain a final method<br>";
    }

    function message2() {
        echo "A final class may also contain a non-final method";
    }
}

$obj1 = new ParentClass();
$obj1->message1();
$obj1->message2();

?>

Because a final class cannot be inherited, it doesn’t matter if it contains final methods. The class can’t be inherited so none of its methods can be inherited or overridden anyway.

final access modifier on a method

A developer might decide to protect only a method from being overridden, instead of the whole class. To block a method from being overridden, we use the final keyword on the method definition.

Syntax:
class ParentClass {

    final function methodName() {}

}
Example: final method
<?php

class ParentClass {

    final function message1() {
        echo "A final class may contain a final method<br>";
    }

    function message2() {
        echo "A final class may also contain a non-final method";
    }
}

class ChildClass extends ParentClass {

    function message1() {
        echo "A final method cannot be overloaded";
    }

}

?>

In the example above, we mark the message1() method as final, indicating that we don’t want any inheriting class to be able to override it.

When we try to override it in the ChildClass, the interpreter raises an error.

Output:
 Fatal error: Cannot override final method ParentClass::message1()

Summary: Points to remember

  • Encapsulation hides members of a class to provide data protection from accidental manipulation.
  • Members can be set to private to only allow access in that specific class.
  • Members can be set to protected to only allow access to that specific class and any that inherit from it.
  • Members can be set to final to protect them from being overridden in child classes.
  • An abstract method does not have an implementation, instead it’s left to the inheriting class to provide it. This forces other developers to follow a strict design.