Introduction:

The aim of this tutorial is to introduce people somewhat familiar with PHP to Object Oriented Programming with that language.

Why version 5+? OOP in version 4 was more or less a joke. The language just wasn't equipped to do things the right way. Instead, bare-bones OOP functionality was bolted onto the language without much forethought or care. PHP made huge strides with version 5, turning its OOP capabilities from laughable to reasonable. PHP isn't Smalltalk, Java, C#, or any language that treats most things as objects, but it's good enough for web programming.

It's hard to discuss OOP without talking about best practices. There's a difference between merely stuffing functions into a class and true OOP, which this tutorial will address.

So, without further ado, let's get started.

Classes and objects and bears, oh my!

Well, there aren't any bears, but the core of OOP revolves around the concepts of a class and an object.

What is a class? A class, in most cases, can be looked at as a blueprint or a mold. It defines the characteristics of an object, but isn't an object itself. A class is also a datatype. That is, something that both represents a certain type of data, and the operations that can be performed on that data.

Example: an integer represents both a 'counting' number (that is, a number without a value to the right of the decimal point), and the operations that can be performed on that number (addition, subtraction, etc.).

When we create a new class, we use existing datatypes to create a more complex datatype.

Example: we want to make a Car class. Well, a car is manufactured by a certain company, so we can store that info as a string. It has a certain amount of horsepower and fuel mileage rating, so we can store those as an integer and floating point number respectively.

So, if a class is the mold/datatype, then what is an object? An individual representation of that mold/datatype. In OOP-speak, we talk of objects as being an instance of a class.

Example: using our Car class, we decide to make a Ferrari object (why go cheap?). Our Ferrari is an instance of Car.

By now, you're probably sick of hypotheticals, so let's look at some code.

Introductory code:

In PHP, class definitions are started, unsurprisingly, by the 'class' keyword. They're block structures, so curly braces denote the beginning and end of a class. Below is a valid (if useless) class:

class Car {}

Not very exciting.

Remember that classes are comprised of values of other, simpler datatypes. In order for our class to know of these values, they must be declared in the class definition. These values are often called the data members of the class. They act as the properties of the class. So, to expand on our Car class...:

class Car
{
   $manufacturerName;
   $horsePower;
   $mpg;
}

Okay, so now we have some properties, how do we access them? How do we even make an object from this?

All objects must be constructed. Whenever an object is created (instantiated, in OOP-speak), a constructor is invoked. A constructor is essentially a function that initializes a particular object's values, and makes it ready for use in the rest of your code. Most of the time, you'll define the constructor yourself. Even if you don't, however, a constructor will still be invoked - the programming language's default constructor. The default constructor creates an object, but with NULL assigned to each data member. So, let's add a constructor to our class:

class Car
{
   $manufacturerName;
   $horsePower;
   $mpg;
 
   function __construct($name, $hp, $mpg)
   {
      $this->manufacturerName = $name;
      $this->horsePower = $hp;
      $this->mpg = $mpg;
   }
}

There's a lot going on here, so let's break it down.

First, all constructors use the '__construct' keyword as their name. And yes, that's two underscore characters before 'construct'.

Second, in this example, the constructor takes three arguments.

Third, the first appearance of the 'this' keyword. 'This' refers to the object that you're presently dealing with. So, if we're trying to construct a Ferrari, 'this' refers to that one particular Ferrari, and nothing else. This will become more clear in further examples. NOTE: When using the 'this' keyword, your syntax must be precise. The variable indicator ('$') precedes only the 'this' keyword and not the data member itself.

So, now that we can create a car, how can we actually invoke the constructor? By simply using the new keyword in the main code, like so:

$myDreamCar = new Car("Ferrari", 523, 10.7);

Great, now we have a car to play with! But, uh...how do we play with it? We need to add functionality to not only our car, but all potential cars. That means we must modify the class again, by adding functions that can act on the class' data members. In OOP-speak, these functions are called methods.

Adding a method to a class is pretty straightforward. You simply define a new function within the class:

class Car
{
   $manufacturerName;
   $horsePower;
   $mpg;
 
   function __construct($name, $hp, $mpg)
   {
      $this->manufacturerName = $name;
      $this->horsePower = $hp;
      $this->mpg = $mpg;
   }
 
   function addNOS($extraHP)
   {
      $this->horsePower += $extraHP;
   }
}

And this is how we invoke that method:

$myDreamCar = new Car("Ferrari", 523, 10.7);
$myDreamCar->addNOS(100);

Pretty easy, right? Well, not so fast.

Access Modifiers (get your hands off my cookies!)

One of the guiding philosophies behind OOP is that datatypes should be encapsulated. Simply put, the main code shouldn't know (or care) about the inner workings of an object. So long as an object behaves in a predictable manner, that should suffice. Moreover, the objects themselves need to be protected from the greater system code as well. An object's innards shouldn't be able to be modified at the drop of a hat. Having one side of the equation know too much about the other leads to coupling, meaning that a change in one part of the code creates a cascade of other changes that need to be made. This is the antithesis of OOP, and steps should be taken to eliminate coupling and promote modularity.

Thankfully, PHP gives us a way to protect the vital parts of our objects: access modifiers.

Access modifiers tell both the system and other coders the availability of an object's members and methods. There are three basic modifiers:

Public: this member or method is freely accessible to be modified/invoked by any other piece of code.

Protected: this member or method is freely accessible to be modified/invoked by any child object, but is hidden from everyone else (child objects will be discussed later).

Private: this member or method cannot be directly accessed by anyone.

The power of these modifiers can be seen when used together. Let's revisit our car class and make some modifications:

class Car
{
   private $manufacturerName;
   private $horsePower;
   private $mpg;
 
   public function __construct($name, $hp, $mpg)
   {
      $this->manufacturerName = $name;
      $this->horsePower = $hp;
      $this->mpg = $mpg;
   }
 
   public function addNOS($extraHP)
   {
      $this->horsePower += $extraHP;
   }
}

As you can see, the data members have been made private. This protects them from being directly accessed by any other code. In fact, attempting to execute something like:

$ferrari = new Car("Ferrari", 523, 10.7);
$ferrari->mpg = 12.3;

Will generate an error.

But, the question remains: why go through all of this if the data members will need to be accessed anyway?

Well, it's true that an object's members will need to be accessed at some point in its lifetime. But, the way in which they're accessed matters. Like I said before, coupling is something to be avoided at all costs. So, to ensure that an object isn't entangled in the program's main code, clear lines of communication need to be established. By forcing the main code to deal with the object in terms of its methods, you ensure that the ways in which the object can be used are predictable and clear. It also promotes modularity, which I'll discuss later.

Conclusion

This concludes the introduction to OOP with PHP. At this point, you should be able to create a class, instantiate an object from that class, and invoke that object's methods. The meat of OOP will be discussed, at least in part, in the next tutorial.

This page was published on It was last revised on

0

1 Comment

  • Votes
  • Oldest
  • Latest
Commented
Updated

The reason for the modifiers falls in concepts like aggregation and composition. Remember that just because you have a member you don't need to expose it.

Think for a second on the concept of a customer (being defined as a legal entity) and that customer has contacts. You wouldn't want to give people the ability to over write the contact list but you might want to give them the ability to add and remove contacts. You would then create and add and remove method that interacts with the contact list inside the class but never exposes the contact list. If you veer need to expose the contact list to display the entries you would have to clone it and pass it back so the list inside the customer class is never directly manipulated by the developer using your API

add a comment
0