Introduction to classes

What is a class?  A class is a blueprint for an object that contains all the code required for the object to interact with it’s surroundings.  Just like the blueprint for a chair details that there will be four legs that touch the floor, and a flat bit to hold some weight, a PHP class does exactly the same thing.  This tutorial is based around a session I did at my workplace on classes and how they can be used.

A class by itself is useless.  Just as you can’t live in the printed plans of a house, but if you take those plans and use them to build a house, then you can live in that.  Creating an object from a class is called instantiation (you’re creating an instance of the class).

Classes define two main things – methods and properties.  The methods are functions that can be called, and properties are values that are attached to the object.  For example a Vehicle class might have a method called refillFuelTank(), and a property called $fuelRemaining.  Let’s look at an example of this Vehicle class.

<?php
class Vehicle
{
  var $fuelRemaining = 0;  // default values - tank starts off empty
  var $exteriorColor = 'red';  // default values
  var $tankSize = 40;  // default values
  var $engineSize = 1600;  // default values
  var $odometer = 0;  // default values
 
  function driveDistance($distance,$speed)
  {
    // Rough formula that means going 50km at 80km/hr w/ a 1.6L car uses 6.4L ...
    $fuelRequired = $distance * $speed * $this->engineSize / 1000 / 1000;
    if ($fuelRequired < $this->fuelRemaining)
    {
      $this->error = 'Not enough fuel to go '.$distance.'km at '.$speed.'km/hr';
      return false;
    }
    $this->fuelRemaining -= $fuelRequired;
    $this->odometer += $distance;
    return true;
  }
 
  function refillTank()
  {
    $this->fuelRemaining = $this->tankSize;
  }
}
?>

This is a pretty simple class that could be used to simulate a vehicle’s fuel consumption.  Of course the formula for fuel consumption is indicative only but you could use this class to find out how far this vehicle goes on a tank of gas. Note the use of the $this variable – this is used to reference the property of the class and can only be used inside a class definition.

Once you have this class in place you can then create a new object from it, customise it as needed and then call the methods in it.  For example:

<?php
  $car = new Vehicle();
  $car->engineSize = 1000;  // from somewhere in Europe :)
  $car->tankSize = 25; // definitely from somewhere in Europe :)
  $car->refillTank();
 
  // Drive this car in 1km chunks until the tank runs dry.
  while ($car->driveDistance(1,50))
    echo '.';
 
  echo "\nThe car was able to drive ".$car->odometer."km before it could go no further.\n";	
?>

Ideally your class will encapsulate all of the required code for the object to interact in it’s environment. You could extend the above class to include methods for loading passengers into the vehicle. There could be a property called maxPassengers, and a method called addPassenger(). When you add a passenger you might have to give the properties of the passenger, for example name and weight and use this to give you a passenger manifest (via a method called showManifest()) and also use the combined weight of the passengers in the fuel consumption calculation.

You will also notice that the class definition allows you to specify default values for the vehicle. In the code where we drive until the tank is dry you see that I’ve manually set the engineSize and tankSize to something different. You can also do this via a method, for example you could have a method called setEngineSize() that internally would set $this->engineSize. You could perform some validation in here to ensure that a 150L engine could not be installed for example.

Constructors

You can also set these values via a special method called the constructor. The constructor method is always run when a new object is created from a class. Here’s an example of a constructor for our Vehicle class:

<?php
 
 
class Vehicle
{
  // Note that we define default values meaning that both engineSize and tankSize are optional
  function __construct($engineSize=1.6,$tankSize=35)
  {
    $this->engineSize = $engineSize;
    $this->tankSize = $tankSize;
  }
}
?>

Now by using the following code you can create a car with a 1.5L engine and a 70L tank:

<?php
  $car = new Vehicle(1.5,70);
?>

Personally I don’t like that way of declaring a constructor as when you look at the instantiation of the $car object you can’t tell what 1.5 or 70 means. Another perfectly acceptable method of doing this is:

<?php
class Vehicle
{
  function __construct($data=null)
  {
    if ($data['tankSize']) $this->tankSize = $data['tankSize'];
    if ($data['engineSize']) $this->tankSize = $data['engineSize'];
  }
}
?>

Now with the above code you can then instantiate the object like so:

<?php
  $car = new Vehicle(array(
    'engineSize'=>1.5,
    'tankSize'=>70
  ));
?>

In my opinion this is far more readable and self documenting as well, although there is no checking to see that you’re not passing in an option that isn’t supported (or misspelt). You could do a check in the Vehicle constructor though if you wanted to.

Destructors

A destructor is another special method of the class and it’s job is to run any cleanup code before the object is destroyed. An object is destroyed when the program terminates, or when you unset the object or redeclare the variable to be something else (the latter of which is considered sloppy coding).

For example when a vehicle object is destroyed we might want to make a note of how much unused fuel there was. Here’s an example:

<?php
class Vehicle
{
  function __destruct()
  {
    echo "This car is being destroyed and there is ".$this->fuelRemaining."L of fuel left.\n";
    echo "It has also traveled ".$this->odometer."km.  Not bad for a ".$this->exteriorColor." car!\n";
  }
}
?>

If you put it all together, this is the output of the script:

bob@sparkie:~$ php vehicle.php 
We made a new car!
.......................................................................
.......................................................................
.......................................................................
.......................................................................
.......................................................................
.......................................................................
.......................................................................
..
The car was able to drive 499km before it could go no further.
This car is being destroyed and there is 0.0499999999998L of fuel left.
It has also traveled 499km.  Not bad for a red car!

That’s all for now on classes – if you have any comments go crazy below.

16 Comments

  • By Maik, February 3, 2009 @ 10:15 pm

    Does NOT work, get 0 meter everytime !

  • By admin, February 3, 2009 @ 10:34 pm

    Can you post the code you used? Also what version of PHP are you using?

  • By Maik, February 3, 2009 @ 11:06 pm

    I changed your code so that it does work, but it gets stuck in an infinite loop.

    php version: 5

  • By Maik, February 3, 2009 @ 11:08 pm

    OOP in PHP
    motorInhoud / 1000 / 1000 ;
    if ($benzineNodig benzineResterend)
    {
    $this -> error =’Niet genoeg benzine om ‘.$afstand.’ km af te leggen met ‘.$snelheid.’ km per uur’;
    return false;
    }

    $this->benzineResterend -= $benzineNodig;
    $this->meter += $afstand;
    return true;
    }

    function tanken()
    {
    $this->benzineResterend = $this->tankInhoud;
    }

    function __destruct()
    {
    echo “Deze auto word vernietigd en heeft nog “.$this->benzineResterend.”L benzine over.\n”;
    echo “Deze auto heeft ook “.$this->meter.”km afgelegd. Niet slecht voor een “.$this->kleur.” auto!\n”;
    }

    function __construct($data=null)
    {
    if ($data['tankInhoud']) $this->tankInhoud = $data['tankInhoud'];
    if($data['motorInhoud']) $this->motorInhoud = $data['motorInhoud'];
    }

    }

    $car2 = new auto(array(
    ‘motorInhoud’=>1.9,
    ‘tankInhoud’=>70
    ));

    while ($car2->rijdAfstand(1,50))
    echo ‘. ‘;

    echo “\n De auto is “. $car2->meter .” km ver gekomen \n”;

    ?>

  • By Maik, February 3, 2009 @ 11:09 pm

    something went wrong, here is my code again:

    motorInhoud / 1000 / 1000 ;
    if ($benzineNodig benzineResterend)
    {
    $this -> error =’Niet genoeg benzine om ‘.$afstand.’ km af te leggen met ‘.$snelheid.’ km per uur’;
    return false;
    }

    $this->benzineResterend -= $benzineNodig;
    $this->meter += $afstand;
    return true;
    }

    function tanken()
    {
    $this->benzineResterend = $this->tankInhoud;
    }

    function __destruct()
    {
    echo “Deze auto word vernietigd en heeft nog “.$this->benzineResterend.”L benzine over.\n”;
    echo “Deze auto heeft ook “.$this->meter.”km afgelegd. Niet slecht voor een “.$this->kleur.” auto!\n”;
    }

    function __construct($data=null)
    {
    if ($data['tankInhoud']) $this->tankInhoud = $data['tankInhoud'];
    if($data['motorInhoud']) $this->motorInhoud = $data['motorInhoud'];
    }

    }

    $car2 = new auto(array(
    ‘motorInhoud’=>1.9,
    ‘tankInhoud’=>70
    ));

    while ($car2->rijdAfstand(1,50))
    echo ‘. ‘;

    echo “\n De auto is “. $car2->meter .” km ver gekomen \n”;

    ?>

  • By Maik, February 3, 2009 @ 11:09 pm

    keeps going wrong, how should i paste the code ?

  • By Maik, February 3, 2009 @ 11:23 pm

    motorInhoud / 1000 / 1000 ;
    if ($benzineNodig benzineResterend)
    {
    $this -> error =’Niet genoeg benzine om ‘.$afstand.’ km af te leggen met ‘.$snelheid.’ km per uur’;
    return false;
    }

    $this->benzineResterend -= $benzineNodig;
    $this->meter += $afstand;
    return true;
    }

    function tanken()
    {
    $this->benzineResterend = $this->tankInhoud;
    }

    function __destruct()
    {
    echo “Deze auto word vernietigd en heeft nog “.$this->benzineResterend.”L benzine over.\n”;
    echo “Deze auto heeft ook “.$this->meter.”km afgelegd. Niet slecht voor een “.$this->kleur.” auto!\n”;
    }

    function __construct($data=null)
    {
    if ($data['tankInhoud']) $this->tankInhoud = $data['tankInhoud'];
    if($data['motorInhoud']) $this->motorInhoud = $data['motorInhoud'];
    }

    }

    $autotje = new auto(array(
    ‘motorInhoud’=>1.6,
    ‘tankInhoud’=>70
    ));

    $autotje -> tanken();

    while ($autotje->rijdAfstand(1,50))
    echo ‘. ‘;

    echo “\n De auto is “. $autotje->meter .” km ver gekomen \n”;

    ?>

  • By Maik, February 4, 2009 @ 12:52 am

    dont know answer ?

  • By Maik, February 5, 2009 @ 7:53 pm

    Could you help me please ?

  • By GuruBob, February 5, 2009 @ 8:46 pm

    Yes, I can … stand by.

  • By GuruBob, February 5, 2009 @ 10:54 pm

    There was a couple of bugs, but I’ve just written and tested this in PHP 5.2.8-cli.

    <?php
    	class Vehicle
    	{
    		function __construct($data=null)
    		{
    			$this->tankSize = ($data['tankSize']) ? $data['tankSize'] : 50;	// Default tank size of 50L
    			$this->engineSize = ($data['engineSize']) ? $data['engineSize'] : 1.6;	// Default engine size of 1.6L
    			$this->exteriorColor = ($data['exteriorColor']) ? $data['exteriorColor'] : 'unpainted';	// Default colour of "unpainted"
    			$this->odometer = 0;	// Every new car starts with zero km on the clock
     
    			echo "(".__FUNCTION__.") We just made a new ".$this->exteriorColor." car that has a ".$this->tankSize."L tank and a ".$this->engineSize." engine.\n";
    		}
     
    		function __destruct()
    		{
    			echo "(".__FUNCTION__.") This car object is being destroyed and there is ".$this->fuelRemaining."L of fuel left.\n";
    			echo "(".__FUNCTION__.") It has also traveled ".$this->odometer."km.  Not bad for a ".$this->exteriorColor." car!\n";
    		}
     
    		function driveDistance($distance,$speed)
    		{
    			// Rough formula that means going 50km at 80km/hr w/ a 1.6L car uses 6.4L ...
    			$fuelRequired = $distance * $speed * $this->engineSize / 1000;
    			// echo "  We are about to drive ".$distance."km at ".$speed."km/hr - that requires ".$fuelRequired."L of fuel\n";
    			if ($fuelRequired > $this->fuelRemaining)
    			{
    				echo "(".__FUNCTION__.") Not enough fuel to go ".$distance."km at ".$speed."km/hr\n";
    				return false;
    			}
    			$this->fuelRemaining -= $fuelRequired;
    			$this->odometer += $distance;
    			return true;
    		}
     
    		function refillTank()
    		{
    			echo "(".__FUNCTION__.") The fuel tank is currently ".ceil(($this->fuelRemaining/$this->tankSize)*100)."% full - we will refill it.\n";
    			$this->fuelRemaining = $this->tankSize;
    			echo "(".__FUNCTION__.") The fuel tank is now ".ceil(($this->fuelRemaining/$this->tankSize)*100)."% full\n";
    		}
    	}
     
    	// ---- Main Program ----
     
    	$car = new Vehicle(array(
    		'engineSize'=>1.6,
    		'tankSize'=>35,
    		'exteriorColor'=>'red'
    	));
     
    	$car->refillTank();
     
    	// Drive this car in 1km chunks until the tank runs dry.
    	echo "Let's drive this car until we run out of fuel!\n";
    	while ($car->driveDistance(1,50))
    		echo '.';
     
    	echo "\nThe car was able to drive ".$car->odometer."km before it could go no further.\n";	
     
    	// End of script - the car object will be destroyed
    ?>
  • By GuruBob, February 5, 2009 @ 10:55 pm

    Oh, and to paste that code in like that:
    < pre lang="php" >
    … paste your code in here …
    < /pre >
    Note I’ve included extra spaces in the preformat tag so they don’t actually preformat this comment.

  • By Maik, February 5, 2009 @ 11:12 pm

    Thanks alot, i spend all day figuring it out, but since i am just starting OOP in php i couldnt find the error.

    Your comments and echo-ing which function you’re calling also really helped.

    Do you got any tips for learning OOP ?

  • By GuruBob, February 5, 2009 @ 11:17 pm

    The best thing is looking for documented examples and asking for help. It certainly helps if you know some of the built in constants (like __FUNCTION__) so you can echo where you’re at in the code. Also if you have access to a PHP debugger (sorry I don’t know any good ones, I have tried many trial versions though) you can also step through the code and watch the variables and objects being created.

    Try to find a real world example that you can apply a class to and use it. If you can make your classes as generic as possible you can reuse them in different projects and increase their power and functionality accordingly.

    What kind of projects are you working on?

  • By Maik, February 5, 2009 @ 11:28 pm

    Allright i’ll look into that.

    I’m learning to write code manually instead of just copy pasting. While doing so i hope to understand the code i’m writing a little bit better.

    My project:
    I’m trying to implement OOP in my own build CMS and eventually have a library/framework for new clients.

    *I’m dutch so please excuse my english and the way i __construct :P sentences*

  • By DroBuddy, July 12, 2009 @ 11:47 am

    Thanks for the tutorial… This is one of the best ones I’ve been able to find and really helps clarify a lot of the issues. I’m still a lil’ confused, but not nearly as much as I was prior to reading this!

    If only someone would take the time to create some good video tuts on this… God, it would make this all so much easier.

    If you are interested in making a screencast on OOPHP, I would truly appreciate it and would be more than glad to put it on WebDevelopmentVideos.com with a link back to your site… Send me an e-mail if you’re interested.

    And, thanks again! Peace.

Other Links to this Post

RSS feed for comments on this post. TrackBack URI

Leave a comment

WordPress Themes