It has been a long time coming, but I’m finally going to wrap my head around Object-Oriented Programming in PHP. It’s something I’ve read about many times before, and even understand the core concepts and principles of OOP, at least in abstract. I’ve just never actually dug in and got my hands dirty with the nitty gritty of how to go about writing in an OOP paradigm.
Before I dig deep into some examples of how a Class might work, I want to define some key terms.
Objects and Classes
In order to clearly get this in my mind, I’m going to use an analogy to highlight the difference between Objects and Classes. In OOP, the two terms are often used seemingly interchangeably, which has led to at least some of my confusion in the past, but they are very different beasts.
The Class can be thought of as a blueprint. It is a design, a template.
The Object is what we build using the blueprint.
So the difference between a Class and an Object is something like the difference between this…
and this…
$this
The pseudo variable $this
is integral to OOP in PHP. This is quite difficult to explain, but put simply it is an internal reference to the current instance of an Object. It is essentially the Class referencing itself, or more specifically, referencing an Object it made itself. It will crop up in some of the examples I’ll be using, and seeing it in action helps to understand it more clearly than a straightforward definition.
Class Properties and Methods
Properties are attributes a Class’s Objects might have. To use the example of a ‘Human’ Object, we might want use the Class to set variables such as height, weight, number of fingers, skin colour, eye colour and so on. These can either be constant or vary between Objects: all our humans might have the same number of fingers but have different coloured eyes, for example. I find it helpful to remember that property is really just a special name for a variable within a Class.
A method is an action a Class’s Objects might take. With the ‘Human’ Object it could be actions such as ‘laugh’, ‘eat’, ‘wear grey t-shirt’ or ‘have water fight with kids’. Method is actually just a special name for a function that exists within a Class.
Properties and methods are declared the same way as ordinary php variables and functions, but with the option to specify how accessible they are to other entities within the code. To understand this, it’s important to grasp that both properties and methods can exist in three distinct states within a Class:
public
– property/method is available from anywhere, other Classes and instances of the Objectprivate
– property/method is visible only within its own Classprotected
– property/method is visible in all Classes that extend current Class, including the parent Class
These concepts will become clearer as I delve into some examples of how Classes operate. So far, I’ve only addressed the fundamental concepts, it’s time to look at how they all work.
Example Class
Below is an example of a very simple Class which has two public properties; title
and source
. It also has a public method, named displayRecipe()
. Because all of these are declared within the Class using the public
access modifier keyword beforehand, they can be accessed and set from outside the Class.
<?php class Recipe { public $title; public $source; public function displayRecipe() { return $this->title . " from " . $this->source; } } // Instantiate the Class $recipe1 = new Recipe(); // Set the public Properties $recipe1->title = 'My First Recipe'; $recipe1->source = 'My Favourite Cookbook'; // Call the public Properties echo $recipe1->title . "\n"; echo $recipe1->source . "\n"; // Call a public Method echo $recipe1->displayRecipe();
Result:
My First Recipe
My Favourite Cookbook
My First Recipe from My Favourite Cookbook
In this example, the Class is called Recipe
, and the Object is contained in the variable $recipe1
. Creating the Object is called ‘instantiating the Class’, as we are creating an instance of a Class Object.
Once we have the Object, because its Class’s properties and methods are all public, we can set them and call them freely from outside the Class.
Getter & Setter Methods
If the properties of a Class are not set to public
, they cannot be accessed directly from outside the Class. The following code will not work, as we are trying to set and get the title
property from outside the Class:
<?php class Recipe { private $title; } // Instantiate the Class $recipe1 = new Recipe(); // Set the public Property $recipe1->title = 'My First Recipe'; // Call the public Property echo $recipe1->title;
Result:
PHP Fatal error: Uncaught Error: Cannot access private property Recipe::$title in /recipes.php:11
Stack trace:
#0 {main}
thrown in /recipes.php on line 11
Instead, it is good practice to use ‘getters and setters’; Methods within the class that are publicly available outside the Class that set and call private Properties. They look something like this:
<?php class Recipe { private $title; public function setTitle( $title ) { $this->title = ucwords($title); } public function getTitle() { return $this->title; } } // Instantiate a Class $recipe1 = new Recipe(); // Call a Setter Method $recipe1->setTitle( 'my first recipe' ); // Call a Getter Method echo $recipe1->getTitle();
Result:
My First Recipe
This is particularly useful because it allows us to do all sorts of things with an Object’s properties before they are set. In this example, I am passing a string of lowercase characters to the setTitle()
method, and it is capitalising every word when the $title
property is set. Obviously this is extremely simple, but this structure could come in very handy when passing variables to methods that could contain unpredictable or insecure values: instead of merely capitalising a string we could instead employ other PHP functions to make the variable safe to use.
Multiple Instances
The whole point of OOP is being able to have multiple, varying instances of similar Objects, but I have not yet demonstrated how to go about doing that. It’s as simple as instantiating the Class multiple times:
<?php class Relic { private $name; private $discovered; public function setName( $name ) { $this->name = ucwords($name); } public function setDiscovered( $discovered ) { $this->discovered = ucwords($discovered); } public function getName() { return $this->name; } public function getDiscovered() { return $this->discovered; } } $relic1 = new Relic(); $relic2 = new Relic(); $relic1->setName( 'mask of tutankhamun' ); $relic2->setName( 'dead sea scrolls' ); $relic1->setDiscovered( 'tomb KV62' ); $relic2->setDiscovered( 'qumran caves' ); echo $relic1->getName() . ' found in ' . $relic1->getDiscovered() . "\n"; echo $relic2->getName() . ' found in ' . $relic2->getDiscovered();
Result:
Mask Of Tutankhamun found in Tomb KV62
Dead Sea Scrolls found in Qumran Caves
Static Methods
By declaring a method as static
, we make it accessible outside the Class without needing to instantiate the Class. To do this, all that is required is to use the keyword static
when declaring the method. It doesn’t matter whether this comes before or after the accessibility modifier, but it’s important to remain consistent. I tend to find that it is declared afterwards, like so:
<?php class Render { public static function display($data) { echo $data; } }
To call a static method we use double colons:
Render::display('Test');
Result:
Test
Magic Methods and Constants
Magic methods are never called directly, but instead they are triggered by certain events in the program. They all have special names beginning with __
, for example __construct()
.
The __construct()
magic method is triggered whenever an Object is created, at the moment the Class is instantiated. It can be useful to use this method to take actions within the Class that are required for all instances. In the Recipe
Class from the earlier examples, none of the recipes would be very useful without a title, so we can pass that in when we first instantiate the Class.
<?php class Recipe { private $title; public function setTitle($title) { if (empty($title)) { $this->title = null; } else { $this->title = ucwords($title); } } public function getTitle() { return $this->title; } public function __construct($title = null) { $this->setTitle($title); } } $recipe1 = new Recipe("my recipe"); $recipe2 = new Recipe(); echo $recipe1->getTitle() . "\n"; echo $recipe2->getTitle();
Result:
My Recipe
In this example, I’ve set the __construct()
method to call the setTitle()
method, passing it the $title
variable that we set when instantiating the Class. In the case of $recipe1
, the $title
property was set to match the string I passed in, but $recipe2
had nothing passed in when it was instantiated, so its $title
is set to null
and so doesn’t show up in the output I’m trying to echo
.
Any sufficiently advanced technology is indistinguishable from magic.
Arthur C. Clarke
Magic constants are similar to magic methods, in that they begin with __
, but they also end with __
. They are not case sensitive, but it is important to be consistent and write code that is easily parsed by humans as well as machines, so the convention is to only use uppercase characters for magic constants. A useful one is __CLASS__
. I’ll demonstrate what it does.
<?php class Recipe { private $title; public function getClass() { return __CLASS__; } } $recipe = new Recipe(); echo $recipe->getClass();
Result:
Recipe
As you can tell, it simply returns the name of the Class itself.
There’s still a huge amount to learn about OOP with PHP, but now I’ve laid the foundations and have a much better grasp of some of the core concepts, I’m quite keen to put some of this into practice.
It’s still magic even if you know how it’s done.
Terry Pratchett
Leave a Reply