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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
$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 usethis
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 10class 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 thethis
keyword:
1 2 3 4 5 6 7 8 9 10class 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 thethis
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 |
|
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 |
|
To instantiate or create a new instance of our class we have to use the new
keyword:
1 2 3 |
|
$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 |
|
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 |
|
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 |
|
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 |
|
Here are the updated versions of our Radio
class and how it is used:
And here is the output: