Object Oriented John (Intro to Objects)
Demitrious S. Kelly on 2002 June 11
Demitrious S. Kelly on 2002 June 11
Most people who are getting into programming (as you might be getting into PHP) know of it, and may even have a bit of a grasp on what OOP is. Whether you do and want a refresher course, or you don't and want an introduction, then you are in the right place!
Anyone who was around when C turned into C++ knows of, and turns pale green at the thought of, OOP (or Object Oriented Programming)... Not necessarily because it was a difficult thing to learn, nor to impliment, but because it required the rethinking, rewriting, and reinventing of many a thousand lines of code, not to mention that it HAD to have been the biggest hardcore techie buzzword of the 90's!
Analogies make explanations easier, convenient, and easier to grasp. This case is no exception. Consider writing a program to be akin to writing a story... Now, when you write a program without objects you are describing a path: e.g. "John's arm moves left half a foot, and down 4 inches". When you use OOP you are describing an object: e.g. "the muscles in John's arm contract, pulling inwards and down".
"What, precisely, is the difference?" is the first question that probably sprang to your mind - and for many, many moons was always the question on my mind.... I always could accomplish what I needed to accomplish with the proper logic and functions.... But one day I found a use for objects, and now I use them wherever they make my life easier. Take the aforementioned analogy (with literary quotes, and all) and imagine John has 18 arms and 17 legs, and could walk in 4 directions at once.... It gets confusing. You'd much rather say "John has 18 arms 17 legs, and could walk in 4 directions at once..." instead of giving all of the precise movements for each leg, arm, speed, velocity, etc over and over again... and, objects let you do just that!
I will warn you--in my experience, you can read about them, and read about them, and read about them, and NEVER grasp why objects are useful--until you find a situation where you are killing yourself with a huge number of lines of code, and start looking for a way to simplify the things. I find that objects generally make life easier when you have a lot to keep track of, and it all pertains to one idea... now, it is NOT necessary that all of the code in an object pertain solely to a single idea (I think I'll probably receive death threats from bitter C converts after saying that) but for the way that MOST people's minds think - it's much easier to say "this is an object, and everything inside pertains to the object". Are you lost yet?
The Anatomy of an Object
A simple object is composed of 3 things (there is MUCH, MUCH more to objects, but these 3 things are beyond the scope of this document). Those are:
1) variables
2) functions
3) a constructor
Anyone who knows objects will yell at me for not instructing you on using "destructors" and "extending objects", or "nested objects"... and I say "shut up and write your own tutorial" in reply--"all": I'm trying to do is show you what you need to GET STARTED (notice the constructor and why objects are useful ;)
An object starts its life as a 'class' which we define in our code. Let's make an object of our name, which is something simple to start with...
We start by declaring a name as a class like so:
<?php
class name {
}
?>
Now, I (and a great many other people) have 3 names - first, middle and last name, so I will need 3 variables, one for each name. Variables which are part of a class are called "member variables". When we define a member variable, we do NOT give it a type (PHP does typecasting for us!) and we DO NOT GIVE IT A VALUE! We just declare it (if you give it a value, the PHP gods will descend from the mountain top and strike at you with serialize()'s lightning bolts )
<?php
class name {
var $first;
var $middle;
var $last;
}
?>
At this point, we technically have workable code as soon as we make an object out of our class:
<?php
class name {
var $firs;
var $midd;
var $last;
}
// We say $myname is a new object of the 'name' class
$myname = new name;
?>
The above code officially creates our first object! Congratulations!
Variables
Ok, we have an object, and we have member variables. Now, how do we access the variables? Well, my friends, that part is easy - we can manipulate most member variables of an object from outside the object with relative ease, and in the manner that you would normally manipulate a variable (by assigning it a value):
<?php
$myname->firs = 'Demitrious';
?>
See, that wasn't so hard! We just set the member variable of the $myname object to 'Demitrious'! Access it much in the same manner:
<?php
echo $myname->firs . '<br>';
?>
This will echo the $firs variable in the $myname object. Now, seems like a good time to point out that when you reference a variable inside of an object, you do not use the variables $ (as you might have already noticed) just ${object}->{membervariable} is enough (and ${object}->${membervariable} WILL NOT WORK, so don't try it - ok, try it... but I'm GONNA say "I told you so!".
Unfortunately this is bland, and all we've done is group together some variables. Let's add a function into the mix, and see what happens. You declare a function inside a variable just like you would in your normal scripting...
like so:
<?php
class name {
var $firs;
var $midd;
var $last;
function set($first, $middle, $last) {
$this->firs=$first;
$this->midd=$middle;
$this->last=$last;
}
function say() {
echo $this->firs . '<br>';
echo $this->midd . '<br>';
echo $this->last . '<br>';
}
}
$myname=new name;
$myname->set('Demitrious', 'Shaun', 'Kelly');
$myname->say();
?>
All right! We've done some important things here that we ought to take a look at. First we made our functions, but the making of the functions is the same as it always was... nothing impressive. But what's inside the functions is important! Look at how set() called the class's member variables: $this->last. It's hard to read it from here, but in this small, but crucial, piece of code is the ingeniousness of classes and objects. $this->last is how PHP differentiates between $myname->last and $yourname->last because $this-> tells PHP, literally, IN THIS OBJECT..., so $this->last says IN THIS OBJECT we're working with the variable $last'. Brilliant!
But still we don't see how this is any different from writing separate functions and variables (well... I'm getting there - and my grand finale, if you don't know objects, will stop you in your tracks and make you take notice!)
We've only got two more things to go over before we get to a more difficult example. So, go grab a soda and hang in there with me.... You'll make it--I promise!
Methods or Member Functions
Two more things about member functions (as functions inside an object/class are often called. Exact termin would be methods): you can call a member function from inside another member function, and you would do it like this:
<?php
class name {
var $firs;
var $midd;
var $last;
function set($first, $middle, $last) {
$this->firs = $first;
$this->midd = $middle;
$this->last = $last;
$this->say();
}
function say() {
echo $this->firs . '<br>';
echo $this->midd . '<br>';
echo $this->last . '<br>';
}
}
$myname = new name;
$myname->set('Demitrious', 'Shaun', 'Kelly');
?>
Notice, in the above example, set() calls the member function say() in EXACTLY the same way that it calls member variables (which helps make the semantics of using objects easier to remember): by using $this->{memberfunction}()
And last but not least we will learn how to make a constructor. Sounds important, doesn't it? Well it is important, but it's easier then you might think. All a constructor is (yeah, I did plan on telling you what it actually did, before telling you how to do it) is a member function that is called AS SOON as the object is made... and all you do is name the function with the same name as the class, like so:
<?php
class name {
var $firs;
var $midd;
var $last;
function name() {
$this->set('Demitrious', 'Shaun', 'Kelly');
}
function set($first, $middle, $last) {
$this->firs = $first;
$this->midd = $middle;
$this->last = $last;
$this->say();
}
function say() {
echo $this->firs . '<br>';
echo $this->midd . '<br>';
echo $this->last . '<br>';
}
}
$myname=new name;
?>
As you can see, when you run the code, name() is automatically run when an object of the name class is run.... This is how we make a constructor.
Now, I would advise you to go and take a friend (boy, girl, or otherwise) out to dinner and a movie, and have a nice evening... because the next part(s) of this document can get a bit hairy, and you might need some R&R time in between sections... And congratulations for making it this far--especially if you understand what's been said (even if you don't know how useful that knowledge is as of yet; you will!)
John's artificial legs
Now, remember when I said, and I quote: "Analogies make explanations easier, convenient, and easier to grasp." This case is no exception. Consider writing a program to be akin to writing a story. Now, when you write a program without objects you are describing a path: e.g. "John's arm moves left half a foot, and down 4 inches". When you use OOP you are describing an object: e.g. "the muscles in John's arm contract, pulling inwards and down." Well, let's take this analogy and make it literal, so you can understand exactly what I mean....
First let's program a normal, non-OOP John:
<?php
// The position (forwards and backwards) of John's leg
$right_leg_x_axis = 0;
// The position (up or down) of John's leg
$right_leg_y_axis = 0;
// The position (left or right) of John's leg
$right_leg_z_axis = 0;
function right_leg($x=0, $y=0, $z=0) {
// Below we need to declare all of John's
// leg position variables to be global, because we use
// and reset them every time the function is called,
// and we want them remembered (plus I'm too lazy
// to call the function specifically with the variables
// we make global)
global $right_leg_x_axis, $right_leg_y_axis, $right_leg_z_axis;
// below here we find the difference between
// all of our positional vars
$xoff = $right_leg_x_axis - $x;
$yoff = $right_leg_y_axis - $y;
$zoff = $right_leg_z_axis - $z;
// now, since he DID move his leg, we need to store the variables
$right_leg_x_axis = $x;
$right_leg_y_axis = $y;
$right_leg_z_axis = $z;
// below is a long list of if's for our output. It decides
// whether things moved to or fro, and tells up by how much...
if( $xoff > 0 ) {
echo "John's leg moved right by $xoff feet<br>";
}
else if( $xoff < 0 ) {
echo "John's leg moved left by $xoff feet<br>";
}
else if( $xoff == 0 ) {
echo "John's leg moved niether right nor left<br>";
}
if( $yoff > 0 ) {
echo "John's leg moved up by $yoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved down by $yoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved niether up nor down<br>";
}
if ( $zoff > 0 ) {
echo "John's leg moved forward by $zoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved backward by $zoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved neither forward nor backward<br>";
}
Return True;
}
// Let's move John's leg now...
right_leg(1, -2, 77);
?>
Object Oriented John
And our OOP version looks similar, but with key differences:
<?php
// Here we 'declare our class' this is very akin to declaring
// a function, except for the fact that a class (also called
// an object) can contain any mixture of variables, and functions
// and, yes, even more classes -- but that gets complicated!
// (we don't want legs growing more legs unless we live near
// a radioactive dump...)
class leg {
var $x; // our x position
var $y; // our y position
var $z; // our z position
// This is starting to sound like those word problems you
// used to hear in school 'if train x is traveling towards
// train y and is moving at z speed, etc, etc, etc... :)
// This is our "constructor". This function can be called in
// the normal way, but what is special about this (special
// enough to warrant a different name) is that it is ALWAYS
// run as soon as the object is created.... It's useful for
// setting up initial variables, etc. You specify something
// as a constructor by giving it the same name as the class
// (e.g. class: leg, function: leg() so if you don't want a
// function to be a constructor then DON'T name it the same
// as the class!
function leg() {
$this->x = 0;
$this->y = 0;
$this->z = 0;
}
// This is our run-of the mill "member function." It's almost
// identical to the non-OOP function except for several points
// 1) We don't declare any of the variables as global, as its
// all contained in a single class
// 2) We don't have to worry about same-named-variables, since
// all of the "member variables" are called as $this->{variable}
function move($x, $y, $z) {
// Below here we find the difference between all of our
// positional vars notice we have a $x created by calling
// the function, AND a $this->x which is the member
// variable $x. These do not interfere with each other
// which is just a nice feature--not having to check.... :)
$xoff = $this->x - $x;
$yoff = $this->y - $y;
$zoff = $this->z - $z;
// since he DID move his leg, we need to store the variables
$this->x = $x;
$this->y = $y;
$this->z = $z;
// Below is a long list of if's for our output. it decides
// whether things moved to or from, and tells up by how much.
if ( $xoff > 0 ) {
echo "John's leg moved right by $xoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved left by $xoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved neither right nor left<br>";
}
if ( $yoff > 0 ) {
echo "John's leg moved up by $yoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved down by $yoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved nerither up nor down<br>";
}
if ( $zoff > 0 ) {
echo "John's leg moved forward by $zoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved backward by $zoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved neither forward nor backward<br>";
}
Return True;
}
}
// We declare $john_left_leg as a new OBJECT. From here
// on out anything inside the object gets referenced like this:
// "echo $john_left_leg->name" will echo the variable $name inside
// of the object $john_left_leg (notice that its $john_left_leg->name
// and NOT $john_left_leg->$name which is an easy mistake to make
$john_left_leg=new leg;
// now we move the leg by calling our "member function" move()
$john_left_leg->move(1, -2, 77);
?>
The differences between two
What is the difference between the two? Well... not a lot when this is all you are doing... but when things get more complicated you will begin to see the value.... Let's give John both his legs (hey would YOU like to not have both your legs? Not that there's anything wrong with missing legs, but I know you'd be angry if someone was just too inconsiderate to program you some legs!)
The non-OOP code we would add to give John his other leg is pretty simple and straightforward to someone who's good at function programming:
<?php
// the position (forwards and backwards) of John's leg
$left_leg_x_axis = 0;
// the position (up or down) of John's leg
$left_leg_y_axis = 0;
// the position (left or right) of John's leg
$left_leg_z_axis = 0;
function left_leg($x=0, $y=0, $z=0) {
global $left_leg_x_axis, $left_leg_y_axis, $left_leg_z_axis;
$xoff = $left_leg_x_axis - $x;
$yoff = $left_leg_y_axis - $y;
$zoff = $left_leg_z_axis - $z;
$left_leg_x_axis = $x;
$left_leg_y_axis = $y;
$left_leg_z_axis = $z;
if ( $xoff > 0 ) {
echo "John's leg moved right by $xoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved left by $xoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved niether right nor left<br>";
}
if ( $yoff > 0 ) {
echo "John's leg moved up by $yoff feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved down by $yoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved niether up nor down<br>";
}
if ( $zoff > 0 ) {
echo "John's leg moved forward by $zof feet<br>";
}
else if ( $xoff < 0 ) {
echo "John's leg moved backward by $zoff feet<br>";
}
else if ( $xoff == 0 ) {
echo "John's leg moved niether forward nor backward<br>";
}
Return True;
}
left_leg(1, -2, 77);
?>
That was easy, don't get me wrong, but it was tedious.. wasn't it?
The differences between two (continued...)
Now, any OOP programmer LAUGHS heartily, and goes to add John's other leg like so:
<?php
$john_right_leg=new leg;
$john_right_leg->move(1, -2, 77);
?>
If that does not get your goose, then consider this: adding another NON-OOP person's legs would result in 70 more lines of code... where as two more OOP legs would only require a measly 4 more lines of code... you do the math, and get back to me after your fingers stop hurting from typing long and hard on the next project that does not have to be either long OR hard!
I think right about now all of you young (or not) novice programmers out there should go and pick up your jaw, and embrace Objects as a thing which makes life easier... :)
But at a cost! Object code IS slower then non object code: consider that:
<?php
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
function icount($vs) {
$var=0;
while($count < $vs) {
$count++;
}
}
$time_start = getmicrotime();
icount(1000000);
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo "Took $time seconds";
?>
took 15.237310051918 seconds to execute, whereas:
<?php
class count {
function icount($vs) {
$count=0;
while($count < $vs) {
$count++;
}
}
}
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$time_start = getmicrotime();
$icount=new count;
$icount->icount(1000000);
$time_end = getmicrotime();
$time = $time_end - $time_start;
echo "Took $time seconds";
?>
took 18.262993097305 seconds!
Cheers!
Demitrious
