<

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x

Advanced Object-Oriented Programming in PHP

Published on
41,645 Points
18,045 Views
16 Endorsements
Last Modified:
Awarded
Community Pick
This article is intended to cover some of the more advanced topics of object-oriented programming (OOP) in PHP, and is intended to follow up on my previous article covering the basics of OOP in PHP. Specifically, this article will teach you all about:

Extending Classes
Protected Scope
Method Overloading
Accessors And Mutators
The __get Method
The __set Method
The __construct Method
Other Magical Methods
Static Stuff
Interfaces

Extending Classes

If you think about it, many things in this world have a main type and then a sub-type. For example, there are humans (main type) and then there are men (sub-type) and women (sub-type). As human beings, men and women share a lot of attributes. We all have arms and legs and a head. We all have faces, toes, and eyeballs, and the list goes on and on of all the things that are similar between men and women. They also do a lot of things that are the same. Most people brush their teeth the same way, work the same way, and eat the same way.

There ARE differences, though, and for the sake of a family-friendly (although incorrect) article, I'm just going to say that the main difference is that all women can have babies and all men cannot have babies.

Now let's say that we're given the task of creating classes to define men and women and what they do. We COULD create two classes that are 99% the same:

<?
class Man {
	public $numHeads = 1;
	public $numArms = 2;
	public $numLegs = 2;
	public $canHaveBabies = false;
	
  public function brushTeeth()
  {
     // lots of code here
  }
  public function goToWork()
  {
     // lots of code here
  }
  public function eatFood()
  {
     // lots of code here
  }
}

class Woman {
	public $numHeads = 1;
	public $numArms = 2;
	public $numLegs = 2;
	public $canHaveBabies = true;
	
  public function brushTeeth()
  {
     // lots of code here
  }
  public function goToWork()
  {
     // lots of code here
  }
  public function eatFood()
  {
     // lots of code here
  }
}
?>

Open in new window

You can already see that it's a lot of duplicate code. And every time we want to add another common property/method for men and women, we have to add it twice - it can quickly become a pain to maintain all of the duplicate code! Just imagine if you also had to define classes for people with both genders or neither genders (I'm avoiding names as not to set off any sensitive web filters) - you would have to maintain FOUR sets of a lot of duplicate code!

It's really inefficient, which is where extending classes comes into play. Extending classes is simply the ability to put all of the common code into one "parent" class (in our example, it would probably be a class called "Human") and then create "child" classes that automatically get all of the parent class code without having to type it in. Then, each child class simply contains whatever is different. So our code might look like this:

<?
class Human {
	public $numHeads = 1;
	public $numArms = 2;
	public $numLegs = 2;
	public $canHaveBabies = false;
	
  public function brushTeeth()
  {
     // lots of code here
  }
  public function goToWork()
  {
     // lots of code here
  }
  public function eatFood()
  {
     // lots of code here
  }
}

class Man extends Human {
	// Our "Human" default already has the correct default for 
	// $canHaveBabies, but just in case the default ever changes later...
	public $canHaveBabies = false;
}

class Woman extends Human{
	public $canHaveBabies = true;
}

class ThreeLeggedMan extends Man {
	public $numLegs = 3;
}
?>

Open in new window

If you notice the last class doesn't extend Human - it extends Man. So, since a ThreeLeggedMan is a Man, and a Man is a Human, then a ThreeLeggedMan will also a Human, too. Keep in mind that you don't HAVE to extend anything, but it can help you if you have a lot of similar classes. Look at these extended classes as an example:

Human
  Man
    ThreeLeggedMan
  Woman
    WomenWithLongHair
      LongHairedBlondes
      LongHairedBrunettes
    WomenWithShortHair
      ShortHairedBlondes
      ShortHairedBrunettes

Open in new window

   
Now, all the ShortHaired and LongHaired classes might be overkill - it's really up to you how precise you want to be with your class definitions.

Protected Scope

In the previous article on the basics of OOP in PHP, I covered public and private scopes. Now we have the "protected" scope, which is very similar to "private" in that any code OUTSIDE of the class cannot touch these variables. the difference between "private" and "protected" is that "private" is accessible only to that EXACT class that has the property. Even child classes can't see or change the private properties of their parent classes. Private is private!

Protected properties are private, but they CAN be accessed by child classes. So if the Human class had a protected property, then any class method inside of the Human class or inside of the Man or Woman or ThreeLeggedMan (etc) classes could access that property. So to recap;

Public - Can be seen and changed by any code, anywhere
Private - Can only be seen and changed by the same class
Protected - Can only be seen and changed by the same class or any of its child classes

Method Overloading

In many languages, overloading means that you have two different class methods with the same name, but different arguments. For example:

public function eatFood($whatFood)
{
  echo "Yum! Eating with bare hands is messy!";
}

public function eatFood($whatFood,$useAFork)
{
  if($useAFork)
  {
  	echo "Yum! Eating with a fork is much cleaner!";
  }
  else
  {
  	echo "Yum! Eating with bare hands is messy!";
  }
}

Open in new window

Overloading in PHP means something different, and is a little too complicated for this article. The above code will give you an error about redeclaring  the same function. However, the traditional concept of overloading is still extremely useful, and can still be accomplished in PHP, but in a slightly different fashion.

There's a PHP function called func_get_args() that comes in handy for this. Let's say you have a function or class method that looks like this:

function myFunction()
{
}

// All of the three below calls are valid:
myFunction();
myFunction(123);
myFunction(123,"abc");

Open in new window

So if all three of those calls are valid, then how would myFunction access the values of 123 and/or "abc" ? This is where func_get_args() comes in. The func_get_args() is used INSIDE of a function or class method and gives you an array that has all the arguments that were passed to the function.

So if myFunction() simply looked like this:

function myFunction()
print_r(func_get_args());
}

Open in new window

Then myFunction() would echo out an empty array (no arguments passed), and myFunction(123) would show an array with 1 element in it containing 123. Likewise, myFunction(123,"abc") would display an array with 2 elements in it containing 123 and "abc".

So by using func_get_args(), you can have one class method handle ALL the different ways that it could be called.

Accessors And Mutators

Every time I hear these terms, I imagine an obsessed science fiction fan coming up with them. I think they are better called "getters" and "setters" because that's what they do.

Accessors ("getters") are functions that simply get/return the value of a class property (usually a private property), while Mutators ("setters") are functions that set/change the value of a class property. There's nothing really technically different about these functions - the functions are just called "Mutators" and "Accessors" because of what they do. Here's an example:

class Human
{
	private $name;
  
	public function getName()
	{
		return $this->name();
	}
  
	public function setName($name)
	{
		$this->name = $name;
	}
}

Open in new window

Naturally, everyone asks, "Why not just make $name into a public property?" The answer has a few different facets, many of which are tied to "proper" programming practices, which suggest that almost all properties be private or protected, and be accessed or changed using these functions.

Then the same people say, "Well, that's stupid and dysfunctional. I'm not going to do that." And nobody is forcing you to. However, proper programming can help you create code that other people can use and change without fully understanding how ALL of the code works.

Imagine your toaster breaks, and you discover that if you open up the toaster and hold down a little lever, the toaster will heat up and toast your bread. That's a solution, right? It might work, but what you don't realize is that by holding down that lever, you're doing something that will eventually cause the toaster to explode.

That's a similar situation here - you might have a class property that contains a name, and a function called changeName(). You COULD simple change the property into a public property and change it directly, which might seem to work at first, but you might not realize that other things need to change in the system whenever the name changes. Unless you change those things manually, as well, you might be causing all sorts of problems. Of course, if you used the changeName() mutator function, it would have updated the $name property AND also changed all the other things in the system that need to be changed.

So as you can guess, accessors and mutators become more and more important as you develop code that will be part of a large system or a complicated class. The more complicated, interweaving code there is, the more important those functions become.

Another reason to use accessors/mutators is to change the values as they are handled. You might have an accessor function that returns a person's $name, but changes it into proper case (upper-case first letter, lower-case for the rest of the name, except for names like McDonald, etc...). A mutator function might take in a value given by someone on the web and run through some security checks before assigning the "cleaned" value to the class property.

The __get Method

There are some "magic" methods that you can define in your classes to make your class "smarter." These magic methods already exist in every class, but PHP handles them by default. However, you can tell PHP that you want to take over that job instead. All you have to do is create a new class method using any of those special names.

The first magic method is __get, which is a very simple accessor function. Whenever you try to get a property that doesn't exist, the __get function is called. Take a look at this code:

class DrSeuss {
  public $doesNotLike = "Green Eggs and Ham";
	public $doesLike = array("Blue Waffles","Red Jelly");
	
  public function __get($var)
  {
    if($var == "likes")
    {
    	return implode(" and ",$this->doesLike);
    }
    else
    {
    	return "... uhhh.... I don't know?";
    }
  }
}

$x = new DrSeuss();
echo "He doesn't like " . $x->doesNotLike; // He doesn't like Green Eggs and Ham

echo "He DOES like " . $x->likes; // He DOES like Blue Waffles and Red Jelly

echo "He isn't SURE about " . $x->unsure; // He isn't SURE about ... uhhh.... I don't know?

Open in new window

So really, __get is just a way of either dealing with specially-named variables, or handling property-not-found errors in a graceful way.

The __set Method

The __set method is just the opposite of __get. Instead of handling the cases where your code is trying to access a property that doesn't exist, the __set method handles the cases where your code tries to SET a property that doesn't exist. I will leave the example up to your imagination.

The __construct Method

The __construct method is called whenever you create a new instance of a class. This is a very frequently-defined magic method, because you can create some really elegant code. Most people use this __construct method to automatically run some extra code as soon as the instance is created, like this:

class Baby {

	public $babyName = "";
  public $currentStatus = "";
	private $secondsLeftOfCrying = 0; // If only this were public...
	
  public function __construct($babyName)
  {
  	$this->babyName = $babyName;
  	$this->startCrying();
  }
  
  private function startCrying()
  {
  	$this->currentStatus = "crying";
  	$this->secondsLeftOfCrying = 85800;
  }
  
}

$UnnamedBaby = new Baby(); // Our __construct requires a $babyName, so this would throw an error.
$FatBaby = new Baby("Junior"); // Junior is born and he immediately starts crying except for 10 minutes each day

Open in new window

Other Magical Methods

There are a lot of other magic methods you can take over, and they're all found here:
http://www.php.net/manual/en/language.oop5.magic.php

Static Stuff

Static properties and methods are simple. So far, whenever we've created a class method, we've had to create an instance of that class FIRST, and THEN call the class method using that instance.

However, when you have a static class method, it simply means that you don't have to create an instance of a class before being able to use it. It looks like this:

class Timer {
  
  public $countDown = 60;
  
  public function resetTimer()
  {
  	// blah blah
  }
  
  public static function getCurrentDateAndTime()
  {
  	return date("m/d/Y H:i:s");
  }
}

echo Timer::getCurrentDateAndTime();

Open in new window

Notice I didn't create an instance of Timer! I simply declared one of the functions/methods to be static, and then called it with the ClassName::StaticMethodName() syntax.

A static class method itself doesn't really have much to do with the class, beyond just being defined inside it. You can't use the $this variable, since $this is a reference to the class instance and static methods don't have instances. In fact, static methods are just like regular functions but they simply happen to be located inside a class.

Being inside the class does give them some advantages. If you're adding a new class into an existing project, then you don't have to worry about accidental, duplicate function names (unless you have the SAME class name defined, which is a different problem). Plus, it sort of groups these types of functions together. You could create a complete function library of static functions that do useful database tasks, then compile it and sell it!

Personally, I find it to be more of a way to keep your functions organized more than anything else. Oh, and it works the same way for properties, too. Just declare your properties as static and you can access them without an instance.

Interfaces

If you hired someone to create a class, but it HAD to have X, Y, and Z methods, then how would you enforce it? You could manually check the code that they give you back, but that could be cumbersome if you did this regularly, and/or had a large number of methods.

Interfaces are poorly named, in my opinion. Interfaces SHOULD be called "Class Skeletons" or "Class Rules" because that's closer to what they are. An interface LOOKS like a class, but without all the code INSIDE your methods. Instead, it looks like a class with a bunch of empty methods:

interface HumanInterface
{
	public function brushTeeth();
	public function eatFood();
}

Open in new window

When you create a class, you can tell it to "implement" an interface, which basically means that the class should obey the rules set by that interface, and it should have all the functions listed in the interface. So if we had this class:

class Human implements HumanInterface
{
  public function brushTeeth()
  {
  	echo "Brush brush brush.";
  }
}

$X = new Human();

Open in new window

Your code would fail, because HumanInterface demands that the class have a brushTeeth AND an eatFood method. If you added an eatFood() method to the class, it would work just fine. So an interface doesn't really do much besides add limits to things. It can be really useful to make sure that newly-hired programmers aren't forgetting to create pieces of code (it happens), or to simply get a birds-eye view of what your classes look like.

There's also such a thing as abstract classes, which work ALMOST like interfaces (and some people use them for the same purpose), but an abstract class is technically a real class, rather than just a set of "rules" that your classes need to follow. Personally, I never use abstract classes.

In Closing

You've only seen the tip of the iceberg. There is a LOT of flexibility in PHP's handling of classes, and the PHP documentation is a great place to find cool tricks (once you understand the principles I've laid out):

http://www.php.net/manual/en/language.oop5.php

I've purposefully skipped some items because they were either too advanced for this article's scope, or were brand-new features to PHP that most people probably don't have access to yet. Again, the PHP documentation is a great place to see the things I've skipped, or figure out why your code is doing X instead of Y.

Thanks for reading!
16
Comment
Author:gr8gonzo
5 Comments
LVL 54

Expert Comment

by:b0lsc0tt
Good article.  Definitely places where I wanted more but I think you did a great job of instructing and enticing.  Thanks for the time to write this and sharing it with us.

What did you find most useful as you learned to write PHP using classes and OOP?  Whether books, sites, or specific projects, etc.  Just curious about anything you felt was especially helpful or key.

bol
0
LVL 54

Expert Comment

by:b0lsc0tt
By the way ... please provide a link here, even if just in a comment, to your "part 1" of this article.  I think many would find it useful, even if it can be pretty easily found in your profile.  Eventually it may be harder to find in your profile so it would be great to provide here.
0
LVL 1

Expert Comment

by:the-exception
Really this is very useful for all the php developers.. Great Job..
1
LVL 36

Expert Comment

by:Loganathan Natarajan
good tutorials, thanks to EE.
0
LVL 111

Expert Comment

by:Ray Paseur
0

Featured Post

Become a Certified Penetration Testing Engineer

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

Join & Write a Comment

Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month