CLASSES
Introduction to PHP classes
While classes and the entire concept of Object Oriented Programming (OOP) is the basis of lots of modern programming languages, PHP was built on the principles of functions instead. Basic support for classes was first introduced in version 4 of PHP but then re-written for version 5, for a more complete OOP support. Today, PHP is definitely usable for working with classes, and while the PHP library still mainly consists of functions, classes are now being added for various purposes. However, the main purpose is of course to write and use your own classes, which is what we will look into during the next chapters.
Classes can be considered as a collection of methods, variables and constants. They often reflect a real-world thing, like a Car class or a Fruit class. You declare a class only once, but you can instantiate as many versions of it as can be contained in memory. An instance of a class is usually referred to as an object.
If you're still a bit confused about what classes are and why you need them, don't worry. In the next chapter, we will write our very first class and use it. Hopefully that will give you a better idea of the entire concept.
Defining and using a class
After the introduction to classes in the previous chapter, we're now ready to write our very own class. It will hold information about a generic user, for instance a user of your website.
A class definition in PHP looks pretty much like a function declaration, but instead of using the function keyword, the class keyword is used. Let's start with a stub for our User class:
<?php class User { } ?>
This is as simple as it gets, and as you can probably imagine, this class can do absolutely nothing at this point. We can still instantiate it though, which is done using the new keyword:
$user = new User();
But since the class can't do anything yet, the $user object is just as useless. Let's remedy that by adding a couple of class variables and a method:
class User { public $name; public $age; public function Describe() { return $this->name . " is " . $this->age . " years old"; } }
Okay, there are a couple of new concepts here. First of all, we declare two class variables, a name and an age. The variable name is prefixed by the access modifier "public", which basically means that the variable can be accessed from outside the class. We will have much more about access modifiers in one of the next chapters.
Next, we define the Describe() function. As you can see, it looks just like a regular function declaration, but with a couple of exceptions. It has the public keyword in front of it, to specify the access modifier. Inside the function, we use the "$this" variable, to access the variables of the class it self. $this is a special variable in PHP, which is available within class functions and always refers to the object from which it is used.
Now, let's try using our new class. The following code should go after the class has been declared or included:
$user = new User(); $user->name = "John Doe"; $user->age = 42; echo $user->Describe();
The first thing you should notice is the use of the -> operator. We used it in the Describe() method as well, and it simply denotes that we wish to access something from the object used before the operator. $user->name is the same as saying "Give me the name variable on the $user object". After that, it's just like assigning a value to a normal variable, which we do twice, for the name and the age of the user object. In the last line, we call the Describe() method on the user object, which will return a string of information, which we then echo out. The result should look something like this:
John Doe is 42 years old
Congratulations, you have just defined and used your first class, but there is much more to classes than this. In the following chapters, we will have a look at all the possibilities of PHP classes.
Constructors and destructors
A constructor and a destructor are special functions which are automatically called when an object is created and destroyed. The constructor is the most useful of the two, especially because it allows you to send parameters along when creating a new object, which can then be used to initialize variables on the object. Here's an example of a class with a simple constructor:
class Animal { public $name = "No-name animal"; public function __construct() { echo "I'm alive!"; } }
As you can see, the constructor looks just like a regular function, except for the fact that it starts with two underscores. In PHP, functions with two underscore characters before the name usually tells you that it's a so-called magic function, a function with a specific purpose and extra functionality, in comparison to normal functions. So, a function with the exact name "__construct", is the constructor function of the class and will be called automatically when the object is created. Let's try doing just that:
$animal = new Animal();
With just that line of code, the object will be created, the constructor called and the lines of code in it executed, which will cause our "I'm alive!" line to be outputted. However, as mentioned previously, a big advantage of the constructor is the ability to pass parameters which can be used to initialize member variables. Let's try doing just that:
<?php class Animal { public $name = "No-name animal"; public function __construct($name) { $this->name = $name; } } $animal = new Animal("Bob the Dog"); echo $animal->name; ?>
Declaring the constructor with parameters is just like declaring a regular function, and passing the parameter(s) is much like calling a regular function, but of course with the "new" keyword that we introduced earlier. A constructor can have as many parameters as you want.
Destructors
A destructor is called when the object is destroyed. In some programming languages, you have to manually dispose of objects you created, but in PHP, it's handled by the Garbage Collector, which keeps an eye on your objects and automatically destroys them when they are no longer needed. Have a look at the following example, which is an extended version of our previous example:
<?php class Animal { public $name = "No-name animal"; public function __construct($name) { echo "I'm alive!"; $this->name = $name; } public function __destruct() { echo "I'm dead now :("; } } $animal = new Animal("Bob"); echo "Name of the animal: " . $animal->name; ?>
As you can see, the destructor is just like a constructor, only the name differs. If you try running this example, you will see first the constructor message, then the name of the animal that we manually output in the last line, and after that, the script ends, the object is destroyed, the destructor is called and the message about our poor animal being dead is outputted.
Visibility
Visibility is a big part of OOP. It allows you to control where your class members can be accessed from, for instance to prevent a certain variable to be modified from outside the class. The default visibility is public, which means that the class members can be accessed from anywhere. This means that declaring the visibility is optional, since it will just fall back to public if there is no access modifier. For backwards compatibility, the old way of declaring a class variable, where you would prefix the variable name with the "var" keyword (this is from PHP 4 and should not be used anymore) will also default to public visibility.
PHP is pretty simple in this area, because it comes with only 3 different access modifiers: private, protected and public.
Private members can only be accessed from inside the class itself.
Protected members can only be accessed from inside the class it self and its child classes.
Public members can be accessed from anywhere - outside the class, inside the class it self and from child classes.
Inheritance
Inheritance is one of the most important aspects of OOP. It allows a class to inherit members from another class. Understanding why this is smart without an example can be pretty difficult, so let's start with one of those.
Imagine that you need to represent various types of animals. You could create a Cat class, a Dog class and so on, but you would probably soon realize that these classes would share quite a bit of functionality. On the other hand, there could be stuff that would have to be specific for each animal. For a case like this, inheritance is really great. The idea is to create a base class, in this case called Animal, and then create a child class for each specific animal you need. Another advantage to this approach is that you will every animal you have will come with the same basic functionality that you can always rely on.
Again, this can seem very theoretic and you might not find it very useful in the beginning, but as you create more advanced websites, you will likely run into situations where inheritance can come in handy. Let's have a look at an example now:
class Animal { public $name; public function Greet() { return "Hello, I'm some sort of animal and my name is " . $this->name; } }
A very simple class, pretty much like the ones we created in a previous chapter. However, "some sort of animal" is not very descriptive, so let's create a child class for a dog:
class Dog extends Animal { }
The dog is declared like a regular class, but after that, we use the extends keyword to tell PHP that the Dog class should inherit from the Animal class. Right now, our Dog class has the exact same functionality as the Animal class. Verify this by running the following code:
$dog = new Dog(); echo $dog->Greet();
You will see that both the name and the Greet() function is still there, but they are also still very anonymous. Let's change that by writing a specific version of the Greet() function for our Dog:
class Dog extends Animal { public function Greet() { return "Hello, I'm a dog and my name is " . $this->name; } }
Notice that we declare the Greet() function again, because we need for it to do something else, but the $name class variable is not declared - we already have that defined on the Animal class, which is just fine. As you can see, even though $name is not declared on the Dog class, we can still use it in its Greet() function. Now, with both classes declared, it's time to test them out. The following code will do that for us:
$animal = new Animal(); echo $animal->Greet(); $animal = new Dog(); $animal->name = "Bob"; echo $animal->Greet();
We start out by creating an instance of an Animal class and then call the Greet() function. The result should be the generic greeting we wrote first. After that, we assign a new instance of the Dog class to the $animal variable, assign a real name to our dog and then call the Greet() function again. This time, the Dog specific Greet() function is used and we get a more specific greeting from our animal, because it's now a dog.
Inheritance works recursively as well - you can create a class that inherits from the Dog class, which in turn inherits from the Animal class, for instance a Puppy class. The Puppy class will then have variables and methods from both the Dog and the Animal class.
Abstract classes
Abstract classes are special because they can never be instantiated. Instead, you typically inherit a set of base functionality from them in a new class. For that reason, they are commonly used as the base classes in a larger class hierarchy. In the chapter on inheritance, we created an Animal class and then a Dog class to inherit from the Animal class. In your project, you may very well decide that no one should be able to instantiate the Animal class, because it's too unspecific, but instead use a specific class inheriting from it. The Animal class will then serve as a base class for our own little collection of animals.
A method can be marked as abstract as well. As soon as you mark a class function as abstract, you have to define the class as abstract as well - only abstract classes can hold abstract functions. Another consequence is that you don't have to (and can't) write any code for the function - it's a declaration only. You would do this to force anyone inheriting from your abstract class to implement this function and write the proper code for it. If you don't, PHP will throw an error. However, abstract classes can also contain non-abstract methods, which allows you to implement basic functionality in the abstract class. Let's go on with an example. Here is the abstract class:
abstract class Animal { public $name; public $age; public function Describe() { return $this->name . ", " . $this->age . " years old"; } abstract public function Greet(); }
As you can see, it looks like a regular exception, but with a couple of differences. The first one is the abstract keyword, which is used to mark both the class it self and the last function as abstract. As mentioned, an abstract function can't contain any body (code), so it's simply ended with a semi-colon as you can see. Now let's create a class that can inherit our Animal class:
class Dog extends Animal { public function Greet() { return "Woof!"; } public function Describe() { return parent::Describe() . ", and I'm a dog!"; } }
As you can see, we implement the both functions from the Animal class. The Greet() function we are forced to implement, since it's marked as abstract - it simply returns a word/sound common to the type of animal we are creating. We are not forced to implement the Describe() function - it's already implemented on the Animal class, but we would like to extend the functionality of it a bit. Now, the cool part is that we can re-use the code implemented in the Animal class, and then add to it as we please. In this case, we use the parent keyword to reference the Animal class, and then we call Describe() function on it. We then add some extra text to the result, to clarify which type of animal we're dealing with. Now, let's try using this new class:
$animal = new Dog(); $animal->name = "Bob"; $animal->age = 7; echo $animal->Describe(); echo $animal->Greet();
Nothing fancy here, really. We just instantiate the Dog class, set the two properties and then call the two methods defined on it. If you test this code, you will see that the Describe() method is now a combination of the Animal and the Dog version, as expected.
Static classes
Since a class can be instantiated more than once, it means that the values it holds, are unique to the instance/object and not the class itself. This also means that you can't use methods or variables on a class without instantiating it first, but there is an exception to this rule. Both variables and methods on a class can be declared as static (also referred to as "shared" in some programming languages), which means that they can be used without instantiating the class first. Since this means that a class variable can be accessed without a specific instance, it also means that there will only be one version of this variable. Another consequence is that a static method cannot access non-static variables and methods, since these require an instance of the class.
In a previous chapter, we wrote a User class. Let's expand it with some static functionality, to see what the fuzz is all about:
<?php class User { public $name; public $age; public static $minimumPasswordLength = 6; public function Describe() { return $this->name . " is " . $this->age . " years old"; } public static function ValidatePassword($password) { if(strlen($password) >= self::$minimumPasswordLength) return true; else return false; } } $password = "test"; if(User::ValidatePassword($password)) echo "Password is valid!"; else echo "Password is NOT valid!"; ?>
What we have done to the class, is adding a single static variable, the $minimumPasswordLength which we set to 6, and then we have added a static function to validate whether a given password is valid. I admit that the validation being performed here is very limited, but obviously it can be expanded. Now, couldn't we just do this as a regular variable and function on the class? Sure we could, but it simply makes more sense to do this statically, since we don't use information specific to one user - the functionality is general, so there's no need to have to instantiate the class to use it.
As you can see, to access our static variable from our static method, we prefix it with the self keyword, which is like this but for accessing static members and constants. Obviously it only works inside the class, so to call the ValidatePassword() function from outside the class, we use the name of the class. You will also notice that accessing static members require the double-colon operator instead of the -> operator, but other than that, it's basically the same.
Class constants
A constant is, just like the name implies, a variable that can never be changed. When you declare a constant, you assign a value to it, and after that, the value will never change. Normally, simple variables are just easier to use, but in certain cases constants are preferable, for instance to signal to other programmers (or your self, in case you forget) that this specific value should not be changed during runtime.
Class constants are just like regular constants, except for the fact that they are declared on a class and therefore also accessed through this specific class. Just like with static members, you use the double-colon operator to access a class constant. Here is a basic example:
<?php class User { const DefaultUsername = "John Doe"; const MinimumPasswordLength = 6; } echo "The default username is " . User::DefaultUsername; echo "The minimum password length is " . User::MinimumPasswordLength; ?>
As you can see, it's much like declaring variables, except there is no access modifier - a constant is always publically available. As required, we immediately assign a value to the constants, which will then stay the same all through execution of the script. To use the constant, we write the name of the class, followed by the double-colon operator and then the name of the constant. That's really all there is to it.
The "final" keyword
In the previous chapters, we saw how we could let a class inherit from another class. We also saw how you could override a function in an inherited class, to replace the behaviour originally provided. However, in some cases you may want to prevent a class from being inherited from or a function to be overridden. This can be done with the final keyword, which simply causes PHP to throw an error if anyone tries to extend your final class or override your final function.
A final class could look like this:
final class Animal { public $name; }
A class with a final function could look like this:
class Animal { final public function Greet() { return "The final word!"; } }
The two can be combined if you need to, but they can also be used independently, as seen in the examples above.