Object-Oriented Programming in PHP 5PrefaceYou may have heard this term somewhere before in your PHP development lifespan, and you may have always wondered what it has meant. Of course, you may not have seen it before in most examples, but it is definitely a much more efficient way of writing code and developing applications or websites.
So what does this 'Object-Oriented' mean? Well, let's go into a pretend situation here.
Think of it like this, and look around you. Literally, everything in your surrounding area is, no matter how you look at it, an object. All of these objects have certain properties and behaviors in how they react in a physical world. A box is a box, and won't move. But if you apply force to it, it will go in the direction you apply force to. A table can hold as many objects you want on top of it so long as the objects on top of it don't break the table. A book can open or close, and contains any amount of pages, so long as there is print to read. All these objects have properties and behaviors, like mass, height, width, and they all have physical positions. They also use certain methods as well to utilize the objects, like you can store objects inside a box once you open it up, so long as there is free space. Or flip to the next page of a book if there are still pages left.
So what's my point? Well, much like we treat physical objects in the world, we tend to treat code as if they were objects as well. Reading this tutorial, you may find that you use a hyperlink to stumble across this. And scrolling down the page requires you to use the scrollbar at the side of a certain type of browser. We treat those things that we overlook so much as objects in code, as in they have their own properties (like where does the hyperlink go to, or how much can the scrollbar go up or down). In Object-Oriented Programming, we write our code as if what we are going to make, is an object.
Some Things to KnowAs much as this may confuse you, we write objects as if they were functions, but we do not call it an object - we call it a
class. The class is the outline for how the object will act and what it can do. From this class, we can create ANY amount of objects we so choose.
Inside this class, we will define functions and variables to use, but there will also be modifiers to affect how they are used - called
visibility modifiers. These visibility modifiers will change who, what and how the functions/variables are used. You'll see soon.
ObjectiveTo fill your brain with the wonders of OOP! (and maybe show you the basic design behind an application/website)
Making Your First ClassSo let's take a look at the following code, and see what it does.
<?php
class MyClass {
public function hello_world(){
print "Hello World!";
}
}
$test = new MyClass;
$test->hello_world();
?>
Okay, let's break it down.
Step 1: we defined a new class that we named 'MyClass'
Step 2: inside this class, we made a new function called 'hello_world()'
Step 3: the definition was to print out the text "Hello World!"
Step 4: near the end of the file we instantiated (created, initialized) a new object of MyClass type
Step 5: we initiated MyClass' hello_world() method
Step 6: the result is a "Hello world!" appearing on your screen
But what's the new syntax for this code? Well let's see what we basicallly used:
1. 'class', which stands for 'we are defining a new class'
2. 'public', which is a visibility modifier which I will discuss in one second
3. 'new', meaning we will create a new object of MyClass
4. '->', meaning "hey, use this object's function named 'hello_world()'!"
There are also the visibility modifiers to discuss.
The visibility modifiers are nothing more than just saying who's allowed to use what and how.
1. 'Public' basically says "hey, anyone can use this function/variable!"
1a. Meaning anything outside the class can set internal variables, which in some cases might not be good
2. 'Protected' is another term for meaning an advanced concept learned later on which you will learn
3. 'Private' means "no one outside my class can use this!"
And that's basically it for now. There are a few other key concepts used in conjunction with visibility, but you will learn those later on.
Making More Advanced ClassesSo let's take a look at another example using variables and maybe more '->' pointers. This time it will feature more methods, and give you a look at more complex logic behind OOP (abbreviated Object-Oriented Programming I will use from now on).
Our second example now:
<?php
class MyMathHomework {
// Let's make a class to do our circular math homework
// So let's store the value Pi for circles
public $pi = M_PI;
public function find_circumference($radius){
// The relationship between Pi and Circumference is
// Circumference / Diameter = Pi
// so Circumference = Diameter * Pi
// And for us, Diameter = 2 * the Radius, which is our input
// So, (2 * Radius) * pi = Circumference
$circumference = (2*$radius) * $this->pi;
print "The circumference of a circle with radius " . $radius . " is " . $circumference . "<br/>";
}
public function find_area($radius){
// The area of a circle is as follows
// Area = Pi * r^2
// or Area = Pi * (r * r)
$area = $this->pi * ($radius*$radius);
print "The area of a circle with radius " . $radius . " is " . $area . "<br/>";
}
public function find_volume($radius, $height){
// Now we're working with cylinders, so we're throwing in the height parameter
// Volume is nothing more than an expansion on area, so
// Volume of a cylinder = area of the circle * height
$volume = ($this->pi * ($radius*$radius)) * $height;
print "The volume of the cylinder with radius " . $radius . " and height ". $height . " is " . $volume . "<br/>";
}
public function find_surface_area($radius, $height){
// Surface area is basically how much space is on the cylinder
// Like say if we wanted to make a label for a can, how much space can we use to make the label
// It's more or less the circumference of the circle * height
$sArea = ($this->pi * (2*$radius)) * $height;
print "The surface area of the cylinder with radius " . $radius . " and height " . $height . " is " . $sArea . "<br/>";
}
}
$math = new MyMathHomework;
$math->find_circumference(5);
$math->find_area(5);
$math->find_volume(5, 4);
$math->find_surface_area(5, 4);
?>
Basically I'm trying to use this as an example for how classes are used. All these functions return relative information regarding area, volume, and whatnot if you just pass the radius and height into the functions.
The variables are used a bit different in OOP. Since they are belonging to the class (or object per say), we use a keyword $this to call them, meaning that we are calling THIS object's property 'whatever', or in the math homework example, THIS homework's Pi variable.
Visibility modifiers affect how these variables are used and accessed as well.
After all this, we're more prepared on handling other types of OOP classes. I'll use another example using something called the Constructor.
ConstructingLet's take a look at how a constructor is used, and basically, what it does.
<?php
class MyConstructor1 {
// Let's test out our construction with a few examples
// We will also use a function inside a class
public function __construct($name){
print "Hello, " . $name . "!";
}
}
class MyConstructor2 {
// Another construction example!
public function MyConstructor2($name){
$this->print_stuff($name);
}
public function print_stuff($name){
print "Hello, ". $name . "!";
}
}
class MyConstructor3 {
// Our last constructor example!
public $xVar;
public function __construct($x){
$this->xVar = $x;
print "Our X-Var is now " . $x . "!";
}
}
$c1 = new MyConstructor1("World");
$c2 = new MyConstructor2("World");
$c3 = new MyConstructor3(5);
?>
Idealy, I hope this portrayed what a constructor is, it's a very simple idea that's easily understandable.
The constructor function basically runs when an object is constructed. Anything that is defined under constructor is ran on creation/instantiation/initialization of an object. Also a constructor method can be defined by either __construct() or 'NameOfClass'().
So it's a good thing to have around, especially when you want things to start RIGHT AWAY. Or if you just feel like saving a line of code maybe.
ToStringSince we learned constructors, we should learn another fantastic method that's hidden away ready to be used, called ToString.
<?php
class Person {
public $name;
public function __construct($name){
$this->name = $name;
}
public function __toString(){
return "Hi! My name is " . $this->name . "!<br/>";
}
}
$joe = new Person("Joe");
$tom = new Person("Tom");
$bob = new Person("Bob");
print $joe;
print $tom;
print $bob;
?>
So it sorta works like that. Think of it now, as every data type when you print them, they run like that. In classical programming languages, the String is an object made up of several characters, and the toString would be printing all those characters in the order they were assembled.
ToString basically allows us to define a set amount of text that is to be returned by the method. So if you used print in conjunction with the object, whatever ToString returned, is printed. This is useful for when you want to iterate objects which contain useful information.
Anyway, the next thing that we will go over quickly is Static.
Static!Static, is a way of saying sort of... fixed, never moving, always there. Sort of like how objects in the physical world have a 'static' position because they won't be moved until force is applied.
It's also another way of declaring functions and variables. Static functions/variables can be used without the actual creation of a class, meaning that it's not a variable/function of an object, but rather of the class.
When designing a static function of the class, it must NOT feature any kind of $this variable inside of it, meaning it can contain no reference to anything that'd be used inside the object (variables or references to other functions).
Let's take a looksie. What if we wanted a way to count how many objects were created? We can do this by creating a static count of all the objects that are constructed.
<?php
class TestStatic {
public static $count;
public function __construct(){
self::$count++;
}
public static function howMany(){
print self::$count . " objects have been created.";
}
}
for($i=0; $i<10; $i++){
$objects[] = new TestStatic;
}
TestStatic::howMany();
?>
Running this will tell us that 10 objects have been created. Of course, the irony in this is that we can also find out how many objects we created by counting that array we stored it in... But I digress.
The static type works in mysterious ways, never needing a direct object to use a variable/function, but rather by calling any function or variable by that of the double colon operator known as 'Scope Resolution operator', which is used primarily for calling functions and defining values.
You will have also noticed the 'self' keyword. This isn't used like it is in Python, trust me. It's simply a constant for the current class name. As you can see, caling a static property or function is used by the format 'ClassName'::property/method, meaning that we needed a class name to use that format. So to reduce our time, we can simply use 'self' as an already defined constant for what class we are currently coding in.
You will see another keyword 'parent' later on which does a similar thing ... whoops, I just spoiled the next section!
Parents and InheritanceParents (or inheritance), in Object-Oriented Programming, is the idea that we can have child classes of parent classes, or in another way, from a parent class, we can have as many child classes we want. And these children may differ from their parents, but will still carry over the same functions and variables from the parent.
How does this work exactly? When defining a class, we can say that we want to
extend on top of a pre-existing class, or state the class is the sub-class of a parent class.
Let's apply ourselves a nice situation here. Or maybe we'll do a familiar example.
A circle (YES, back to circles) is one of the basic two-dimensional shapes in math. When moving into three-dimensional math, the circle becomes the cylidner. So the cylinder pretty much inherits all of the circle's old properties and applies new properties to it. Let's write an example about these two classes.
<?php
// You may notice I'm using a different naming style for the functions
class Circle {
public $radius;
public function __construct($radius){
$this->radius = $radius;
}
public function getRadius(){
return $this->radius;
}
public function getArea(){
// Remember this? pi * (radius*radius)
// M_PI is the constant for pi, no need to keep it as a variable
return ($this->radius*$this->radius) * M_PI;
}
public function getCircumference(){
// Circumference = 2*radius * pi
return ($this->radius*2) * M_PI;
}
}
class Cylinder extends Circle {
public $height;
public function __construct($radius, $height){
// When we inherit, the constructor is completely different, unless we do...
parent::__construct($radius);
// Hah! A call back to our parent's old constructor method
// We can do this when we are calling methods from our previous class
// Using $this->__construct() might not be a good idea...
// And let's set the height
$this->height = $height;
}
public function getVolume(){
return $this->getArea() * $this->height;
}
public function getSurfaceArea(){
return $this->getCircumference() * $this->height;
}
}
$circle = new Circle(5);
$cyl = new Cylinder(5, 4);
print "Circle area: " . $circle->getArea();
print "Circle circumference: " . $circle->getCircumference();
print "Cylinder volume: " . $cyl->getVolume();
print "Cylinder surface area: " . $cyl->getSurfaceArea();
?>
As you can see, functions and variables will carry over, but not everything works like it should. Using parent::__construct() is a better idea than $this->__construct(), because you are calling a method you are defining then. $this points to the class, while 'parent' points to the parent class. So if you use $this, you might just end up with a recursive calling function leading you nowhere.
Of course, we can also apply the parent::function/property tactic elsewhere, but since I weaned you into using $this, I'll stick to that.
Here's a few more stupid examples to help you understand inheritance better.
<?php
class Human {
...
}
class Joe extends Human {
Yes I am aware this isn't a good example
}
class Car {
...
}
class AwesomeCar extends Car {
You can't make an awesome car without regular car properties
}
class BasicComputer {
...
}
class BetterComputer extends BasicComputer {
You need all the basic computer stuff before making better computers
}
class Building {
...
}
class AnyOtherKindOfBuilding extends Building {
It is true that we need those regular building properties for any given building
}
?>
Lastly, remember the visibility mod 'protected'? Well guess where that goes.
2. 'protected' - only accessible by the class or extended classes
Basically meaning that anything defined by protected is only used by the parent class and children classes. Pretty useful for when you build classes and plan on using things for classes made later on.
So moving on, we'll hit another topic.
Class AbstractionI showed some pretty horrific examples, all of which will be used probably better here, or maybe. I don't know. I like to keep things fresh, but I'll introduce
class abstraction here.
Abstract is the idea that a class can never exist, but can be extended from. Kind of like how we can never have just a regular 'Car' or 'Building', but extensions on those ideas. In class abstraction, we define values and functions to be abstract. If a class has one abstract function or property, the class must be abstract. And we don't even need to define all methods in an abstract class. If we do not define it in the abstract class, we hint that it must be defined in the extended classes.
Let's look at my new Kitty example.
<?php
abstract class AbstractCat {
// We have to define this method in extended classes
abstract public function printName($name);
// Of course all kitties meow, so let's throw in a meow method
public function meow(){
return "Meow!";
}
}
class CoolCat extends AbstractCat {
public function __construct($name){
$this->printName($name);
}
public function printName($name){
print $this->meow() . " My name is " . $name . " the Cat!<br/>";
}
}
$tom = new CoolCat("Tommy");
?>
Now, I never actually said class abstraction is best used everywhere, but it's a good idea, and definitely up there with the Static topic under either 'cool' or 'confusing'.
The next half of the tutorial is in the following post!