Skip to content

Lecture Notes - Week 13

Readings

  • Chapters:
    • 26 - Introduction to Object Oriented Programming in PHP: pgs. 451 - 464
  • Anything else you can find on Object Oriented Programming

Screencast - Week 13

Outline of Topics

  • Introduction to OOP
  • Classes
  • Properties
  • Encapsulation Using Access Modifiers
  • Accessor Methods
  • The $this Variable
  • General Purpose Methods
  • Instantiating and Using a Class
  • Validating Input to a Setter Method

Lecture

Introduction to Object-Oriented Programming

Object-Oriented Programming (OOP) is a programming paradigm that allows for a more modular way to develop programs. Many modern programming languages have OOP features, and PHP is no exception. There are many conceptual components to OOP. At its most basic level, it allows for combining what a program knows (its data) and what a program does (its functionality) into modular components. This approach is different from basic procedural-based programming, where you have many functions separated from the data that they typically work on. This lecture gives a brief overview of object-oriented programming using PHP.

Classes

Classes organize code into modular components. It is typical to put a single class into its own file. In PHP, you define a class using the class keyword:

1
2
3
4
5
<?php
    class Radio
    {

    }

In this example, we would probably want to name this file Radio.php.

Class names follow the same rules as variable names. However, unlike variable names, class names are not case-sensitive. In practice, the coding standard for naming classes is to start the first word with an upper-case letter and to start every word in the class name with an upper-case letter (i.e., CustomerAccount). This convention is known as StudlyCaps.

One thing to keep in mind about classes is that they are like blueprints or recipes for PHP objects. We explore this later when discussing the difference between an instance of a class—known as an object—and the class definition itself.

Properties

Of course, we need to add data to our classes. In some programming languages, these are called instance or class member variables. In PHP, we call them properties.

Using our Radio example, here are a few properties:

1
2
3
4
5
6
7
<?php
    class Radio
    {
        private $powered;   // true or false
        private $volume;    // 0 - 10
        private $channel;   // 535kHz - 1700kHz, 87.5MHz - 108MHz
    }

On Class Design

As mentioned previously, at the most basic level, a class should define what a program knows (its data) and what a program does (its functionality). Ideally, in object design, you want to think of your class as a single thing. In this case, we are modeling the concept of a radio in software. Before writing any code, think about how one would interact with our radio. Since this is a simple example, we need our radio to know (i.e., hold data for) whether it is on or off, its volume, and what channel or frequency it is set to. Likewise, we also need functionality to turn on and off the radio, set its volume, and change its channel or frequency. The properties and methods your class needs should be informed by your software requirements. We will fill this in when we talk about methods.

Encapsulation Using Access Modifiers

So, what’s the meaning of putting private before our properties?

The keyword private is what’s known as an access modifier. PHP calls this visibility and uses it to restrict access to properties and methods. There are three levels of access to properties and methods: private, protected, and public.

  • private means only the code within the class can access a property or call a method.
  • protected means only the code within this class or subclasses of it can gain access to the property or method.
  • public means everyone can gain access to the property or method.

In object-oriented programming, it is a best practice to restrict access to your properties by making them private. Then, add public methods that grant read or write access to these properties. This is the principle of encapsulation and is one of the main pillars of OOP.

Accessor Methods

To add functionality to our class, we create a method. A method is a fancy OOP term we use that means the same thing as a function, except that we are embedding our methods inside our class. The OOP idea behind methods is that they manipulate or get the data in our class.

If we want to manipulate the data in our Radio class, we need methods to set the data like channel or volume. Likewise, if we’re going to retrieve data from our class, we need methods that get this data. We typically call these accessor methods getters and setters.

The convention used for creating getters and setters is to put either the word get or set in front of our property and capitalize the first letter of each word in the property (i.e., "camel-case" style). We usually make the getters public, and we often make the setters public.

Although this is a more advanced topic, you should think about how code interacts with objects created from your classes during the object’s life. You have the freedom to design a class that allows users of these objects to manipulate data within the object throughout the life of the object or only upon the creation of the object. This concept is known as the “mutability” of your object. If you create ANY setters in your class with public access, your object is known to be mutable (i.e., changeable). Conversely, if you create ALL the setters in your class with private—or possibly protected—access, your object is known to be immutable (i.e., unchangeable). You might be asking, how do you even set the properties of an object if it is immutable? Immutable objects must have their properties set upon construction. In the Introduction to Object-Oriented Programming in PHP I show you how to create a constructor. Immutable objects tend to be preferred because they’ve been shown to be less error-prone.

So, to create getters for our Radio class we need the following methods:

  • getPowered()
  • getVolume()
  • getChannel()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
   class Radio
   {
        private $powered;   // true or false
        private $volume;    // 0 - 10
        private $channel;   // 535kHz - 1700kHz, 87.5MHz - 108MHz

        // Getters
        public function getPowered()
        {
            return $this->powered;
        }

        public function getVolume()
        {
            return $this->volume;
        }

        public function getChannel()
        {
            return $this->channel;
        }
   }

Note the getters have public access so users of our class can retrieve the state of the properties.

The setters for our Radio class whould follow the same convention and be named:

  • setPowered()
  • setVolume()
  • setChannel()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
   class Radio
   {
      private $powered;   // true or false
      private $volume;    // 0 - 10
      private $channel;   // 535kHz - 1700kHz, 87.5MHz - 108MHz

      // ...

      // Setters
      public function setPowered($powered)
      {
         $this->powered = $powered;
      }

      public function setVolume($volume)
      {
         $this->volume = $volume;
      }

      public function setChannel($channel)
      {
         $this->channel = $channel;
      }
   }

The setters have public access, which means objects created from this class will be mutable.

The $this Variable

In the above getters and setters, we made a reference to the $this variable:

1
2
3
return $this->volume;
...
$this->volume = $volume;
The $this variable is a built-in variable available to all classes. It refers to the current object of the class, or this specific instance of this class. To use a class, it has to be “instantiated.” The $this variable refers to just this particular instance of the class. -> is the object operator and allows you to reference the properties or methods of a class by value. PHP requires using $this-> to access these properties or methods, unlike other languages like Java.

Okay, time for me to rant again...

Why Don’t Other Languages Require the $this Keyword?

Welp, that’s a good question, and it’s something PHP gets right. Other programming languages such as Java, C#, and C++ also use the this keyword to refer to class instance variables. However, it is not required to use this in these other languages. It is meant as a convenience to leave it out. I feel it is a mistake not to require the use of the this keyword. Consider the example written in Java:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Radio
{
   private int _volume; // 0 - 10
   ...
   public void setVolume(int volume)
   {
       _volume = volume;
   }
   ...
}

Without requiring the use of the this keyword, we have to make up a scheme for how we differentiate instance variables from our local variables. Prefixing instance variable names with an underscore (_) is one of the typical ways I’ve seen this done.

The problem with leaving out the this keyword is two-fold. First, we require a future developer maintaining this code to know the style of creating instance variables is to precede them with an underscore. Second, it’s hard at first glance to understand that the variables with underscores are instance variables. All developers have to remember not to name local variables starting with an underscore. Contrast the previous example with the same Java code rewritten to use the this keyword:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Radio
{
   private int volume; // 0 - 10
   // ...
   public void setVolume(int volume)
   {
       this.volume = volume;
   }
   // ...
}

The above example is unambiguous and leaves no doubt as to the intent of the code. It does not rely on unenforceable naming schemes for instance variables, all to get around not having to use the this keyword. You should always use the this keyword when directly referencing an instance variable in any programming language. Thank goodness PHP makes this a requirement!

I'm done ranting 😜

General Purpose Methods

In addition to getters and setters, your class can include utility methods to perform various tasks. For example, many radios have a scan button to look for the next channel with a strong signal. These methods don’t have to change your object state (i.e., modify properties) but they may calculate or perform some operation based on your properties:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
    class Radio 
    {
        public function scanChannels() 
        {
            // find the next channel with a strong signal
        }

        public function getCurrentSong() 
        {
            // reads live metadata from current channel about current song
            // being played and returns song title, etc...
        }
    }

Let's take a look at our Radio class so far (version 1).

Instantiating and Using a Class

Instantiating classes as objects and creating multiple instances of that class demonstrates another powerful concept of OOP. In the same way, you can have multiple variables that are strings, integers, etc., a class is another more complex data type that you can use in this way.

To use our class, we first need to include it in a PHP script:

1
require_once('Radio.php');

To instantiate or create a new instance of our class we have to use the new keyword:

1
2
3
require_once('Radio.php');

$car_radio = new Radio();

$car_radio is now referencing a new instance which is an object of the Radio class. Note the () following the class name Radio is the default constructor. As mentioned earlier, we can create multiple instances from our single Radio class:

1
2
3
4
require_once('Radio.php');

$car_radio = new Radio();
$boat_radio = new Radio();

It is best to think of a class as a recipe for making something like cookies and a class’s object to fulfill that recipe (i.e., a batch of chocolate chip cookies—yum!😋) Next, we can use our object:

1
2
3
$car_radio->setVolume(4);

echo 'My car radio\'s volume is set to: ' . $car_radio->getVolume() . '.';

Notice again that we use the object operator (->) to reference the setVolume() method. We can reference any property or method that has public visibility. OOP is a deep topic. Check out what the PHP Manual has to say regarding classes and objects.

Let's take a look at our useRadio test driver so far (version 1).

Validating Input to a Setter Method

Frequently, we need to constrain the input to our methods. For example, in our Radio class, volume settings will have an upper and lower limit. Many entertainment centers have a volume setting between 0 and 10. Let’s add some class constants for these to our Radio class:

1
2
3
4
5
6
7
8
<?php
     class Radio
     {
        const MIN_VOLUME = 0;
        const MAX_VOLUME = 10;

        // ...
    }

In our setVolume() method, we get access to these class constants by using self::. self represents the class’s self, and the :: is called the scope resolution operator. It is needed when referencing constants inside the class. You also use the :: when referencing external variables, but you use the name of the class instead. For example, we can update setVolume() to ensure a user can’t set it outside of the allowable range:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
   class Radio
   {
      const MIN_VOLUME = 0;
      const MAX_VOLUME = 10;
      // ...

      public function setVolume($volume)
      {
         if ($volume < self::MIN_VOLUME)
         {
            $volume = self::MIN_VOLUME;
         }
         else if ($volume > self::MAX_VOLUME)
         {
            $volume = self::MAX_VOLUME;
         }

         $this->volume = $volume;
      }

      // ...
   }

Here are the updated versions of our Radio class and how it is used:

And here is the output:

Week 13 Lab