SiteCrafting, Inc.
Objectifying Code is Not Degrading
What?
So what is a class exactly? And what does it have to do with objects? Also, why do the objects have to be oriented? It's actually easier if we understand what an object is first and go from there. An object in PHP is, just like in the real world, a noun. It is a thing with which we can interact and observe.
Just like man-made objects in the real world, PHP objects require some sort of schematic or blueprint that outlines what it looks like and how it works. Enter: the class. In PHP, a class provides just such a blueprint from which objects can be created.
Syntax
In its most basic form, a class is defined with two words and a pair of brackets:
class Car {
}
While a class as simple as this may be approachable and not very intimidating, it's about as useful as a screen door on a submarine. Think of the above as the blank sheet on which you'll write your blueprint. Every addition beyond this point is simply made to make the class more useful.
Components
Classes can consist of a number of components, none of which are actually required (but again, think of screen doors and submarines). There are three basic components available to you: member variables, member functions, and class constants (for now, just ignore the public keyword - we'll cover that later).
class Car {
// Class Constants
const YEAR_CLASSIC = 1971;
// Member Variables
public $year;
public $make;
public $model;
public $color;
public function __construct() {
$this->year = 2011;
$this->make = 'BMW';
$this->model = '335i';
$this->color = 'black';
}
public function showStats() {
echo 'Year: ' . $this->year . '<br />';
echo 'Make: ' . $this->make . '<br />';
echo 'Model: ' . $this->model . '<br />';
echo 'Color: ' . $this->color . '<br />';
}
}
Member Variables
Member variables work just like normal variables with the exception that they are directly associated with the class. Member variables can be used to store information about an object for later use. In our car example, we'll store some useful bits of info like the year, make, model, and color of the car.
Class Constants
Class constants represent values that cannot be changed at runtime. This basically makes them read-only public member variables. Because the value of a class constant cannot be changed once set, a developer can trust that the value assigned will always remain constant. In our car class, we can use a class constant to define the year before which a car can be considered a classic (1971 will make that anything 50 years or older).
Member Functions
Member functions are functions placed inside a class. They can be used to perform actions on an object, get information about an object, or can even be used inside the object hidden away from code outside the class. For our car class, we can use it to output some of the info we stored in our member variables.
The Constructor
You may have noticed an oddly named function in there called __construct(). This is actually a special case that is handled differently from the the others. It is known as the constructor and is automatically triggered when creating a new object using the $myCar = new Car($param1, $param2, [...]) syntax. Just like normal functions, it can accept parameters as well. Any code that you want to be executed when a new object is created should be placed in here.
All Together Now
At this point we're the proud new owners of a Car class, complete with information about its make and model, as well as a way to show off that info. Let's see it in action:
// Create a new instance.
$myCar = new Car();
// Show of some stats.
$myCar->showStats();
/*
Produces the output:
Year: 2011<br />
Make: BMW<br />
Model: 335i<br />
Color: black<br />
*/
Static vs. Instance
Now that we've got our basic class set up, let's take a moment to consider the difference between a static and instance context. First, remember that the Car class is our blueprint. In order to actually use it, we had to create, or instantiate, a new object. Every time we do this, we are creating a new self-contained copy called an instance. Any changes we make to one instance will not affect any other instances we create.
$myCar = new Car();
$yourCar = new Car();
// Lets change your car to a red chevy Camaro.
$yourCar->make = 'Chevrolet';
$yourCar->model = 'Camaro';
$yourCar->color = 'red';
// Notice how my car is still a black BMW.
$myCar->showStats();
// But your car is now a red Camaro.
$yourCar->showStats();
So what about this static context? Sadly, it does not make your hair do crazy things. Instead it provides a way to specify values and functions that exist outside of class instances that might still be related to what the class is designed to do.
To illustrate this, lets take our Car class and add a static function that calculates whether a car built in a specific year is considered a classic:
class Car {
/*
... we'll hide the code we've already written ...
/*
public static function isClassicYear($year) {
if($year < self::YEAR_CLASSIC) {
return true;
}
else {
return false;
}
}
}
// Now we can try it out.
if(Car::isClassicYear($myCar->year)) {
echo 'My car is a classic!';
}
else {
echo 'My car is too shiny and new!';
}
As you can see, this particular piece of code doesn't relate to a specific car instance (say $yourCar or $myCar), but it still makes sense to contain it within the class. Notice that when making calls to static functions or variables, we use the class name (or self when inside the class) followed by a double colon.
Inheritance
Until now we've been working with a single class. What if we wanted to create another class that was similar to Car, but was a bit more specific. We could just copy and paste the code for our Car class, rename it to Hatchback, and then add some functions related to hatchbacks. This could get a little messy if we did this a few more times (say with a Sedan, Minivan, and Truck class).
Extending
Wouldn't it be great if we could just say "this is just like a Car, except for a couple of things..." As it turns out, you can do just that using the concept of inheritance. Just like people, classes can have a family tree with parents and children. Also just like people, child classes inherit all the traits of their parent classes. Using the keyword extends, let's extend our Car class to make the child class Hatchback.
class Hatchback extends Car {
public $hatchIsOpen = false;
public function openHatch() {
if(!$this->hatchIsOpen) {
$this->hatchIsOpen = true;
}
}
}
// Now let's give it a try.
$myNewCar = new Hatchback();
// The new Hatchback class can do everything the Car class can.
$myNewCar->year = 2008;
$myNewCar->make = 'Mini';
$myNewCar->model = 'Cooper';
$myNewCar->color = 'dark silver';
$myNewCar->showStats();
// It can also do something new.
$myNewCar->openHatch();
So what happens if we define a function in Hatchback that already exists in Car? That practice is known as overriding and is both allowed and quite common. The result of overriding a function is that the new function replaces the old one (naturally this only happens for the child class).
class Hatchback extends Car {
/*
... again lets hide the code we've already written ...
*/
public function showStats() {
parent::showStats();
echo 'Type: hatchback<br />';
}
}
// Now let's give it a try.
$myNewCar = new Hatchback();
$myNewCar->year = 2008;
$myNewCar->make = 'Mini';
$myNewCar->model = 'Cooper';
$myNewCar->color = 'dark silver';
$myNewCar->showStats();
/*
Produces the output:
Year: 2008<br />
Make: Mini<br />
Model: Cooper<br />
Color: dark silver<br />
Type: hatchback<br />
*/
Now wait a second, didn't I just say the new function would replace the old one? Why, then, is the output from the old function still showing up? In this example, I decided to sneak in one additional feature. Sometimes you don't want to replace the parent function, but add to it instead. The line parent::showStats() does just that. It provides a way for you to run a function (or access a variable) from the parent class.
Scope
Since you've been patiently waiting, I think it's time to finally explain the purpose of that public keyword along with its two cousins: private and protected. These keywords define the scope of a function or variable, which in turn allows you to restrict the way in which they are used. Let's add some different variables to our Car class and then explore how they work.
Public
Defining a function or variable as public means that they can be accessed from anywhere (outside the class, inside the class, and inside any child class).
// This works:
class Car {
/*
... you know the drill ...
*/
public $licensePlate = 'S1TCRFT';
public function showLicensePlate() {
echo $this->licensePlate;
}
}
// So does this:
$myCar = new Car();
echo $myCar->licensePlate;
// Also this:
class Sedan extends Car {
public function changeLicensePlate($new) {
$this->licensePlate = $new;
}
}
Private
Functions and variables marked as private can only be accessed from within the same class. Accessing one from outside the class or even from within a child class will trigger an error.
// This works:
class Car {
/*
... nothing to see here ...
*/
private $unlockCode = '2725';
public function unlockWithCode($code) {
if($code == $this->unlockCode) {
echo "Unlocked!";
}
else {
echo "Wrong code!";
}
}
}
// But this doesn't work:
$myCar = new Car();
echo $myCar->unlockCode;
// And neither does this:
class Minivan extends Car {
public function changeUnlockCode($code) {
$this->unlockCode = $code;
}
}
Protected
Variables and functions that are protected are the more easy-going cousins to private ones. They still can't be accessed from outside the class, but child classes are allowed to use/manipulate them.
// This still works:
class Car {
/*
... zzz ...
*/
protected $vin = '1MGCM82633A004352';
public function showVin() {
echo $this->vin;
}
}
// This still doesn't work:
$myCar = new Car();
echo $myCar->vin;
// But this does work:
class Truck extends Car {
public function changeVin($newVin) {
$this->vin = $newVin;
}
}
Conclusion
Congratulations! If you made it this far without any medication, consider yourself a master of focus and your brain a saturated sponge of knowledge! You should now have the basics covered and have taken your first steps towards PHP guru-dom. Feel free to ask questions or share your thoughts in the comments and stay tuned for the next episode!
by Nick Williams | 8/26/2011 12:06pm | Comments (0)
No comments found.