(click anywhere to close)
OPEN MENU

[PHP] Objects II

category: Website | course: PHP | difficulty:

Now that we know how to create objects from our template class, all we really need to do is upgrade the template class to achieve more complex or sophisticated objects.

Auto-loading

As a project grows in size (as it often does), you’re going to be working with lots of classes. It’s a custom, therefore, to put every class into its own separate PHP file. So, for example, the class User is put in the file User.php. This way you can easily keep track of all classes, and simply include all the classes you’re going to need at the top of a file.

But, it’s a lot of hard work to copy around these includes from file to file, which is why PHP allows you to auto-load all your classes. To do so, use

spl_autoload_register(function($name) { include <find correct file using $name>; });
//Say we have classes saved inside the files User.php, Comment.php, BlogPost.php
spl_autoload_register(function($name) {
	include "$name.php";
});

//The autoload will automatically load the User.php file when we try to create an object from it.
$user = new User();

//The other two files are not loaded, as we don't need them. Saves time!

Inheritance

One of the best things about objects and classes, is that you can use inheritance. This means that you can create a class that is a child of another class (a “subclass”), and therefore automatically inherits all the properties and methods of its parent. Using this, you can create huge classes that contain some general functionality and variables, and then create subclasses that automatically inherit this general functionality and add their own special bag of tricks.

To create a subclass, simply extend another class:

class SomeSubClass extends SomeParentClass
class Product {
	public $price = 10;
	public $manufacturer = "LEGO";
	public $reviews = 9.6;
}

//A product on sale extends the general product class, and adds a discount
class SaleProduct extends Product {
	public $discount = 0.8;
}

$new_item = new SaleProduct();
echo "The final price is " . ($new_item->discount * $new_item->price) . " euros.";

//Prints: The final price is 8 euros.

The parent class must be defined first in the file, otherwise PHP doesn’t know what to extend.

Traits

Instead of inheriting from complete classes, we can also just save a bunch of methods and properties under a certain name, and copy this code around inside other classes. In other words, we let multiple classes share the same traits. To create a trait, use

trait SomeTraitName { code }

To include or use it inside some other class, use (not surprisingly)

use SomeTraitName;
class Product {
	public $price = 10;
	public $manufacturer = "LEGO";
	public $reviews = 9.6;
}

trait Discount {
	public $discount = 0.8;
	function calculate_price() {
		return ($this->discount * $this->price);
	}
} 

class SaleProduct extends Product {
	use Discount;
}

$new_item = new SaleProduct();
echo "The final price is " . $new_item->calculate_price() . " euros.";

//Prints: The final price is 8 euros.

Abstract Classes

Remember when I told you about the huge classes and the subclasses? (You should, I just told you.) Well, in most cases, you aren’t going to create an object from the huge class – you’ll only be creating objects from the subclasses.

For example, you could have a general class called “vehicle”, and lots of smaller classes called “car” and “truck” that extend this general class. If you were to attach functions to the vehicle class such as “accelerate” and “brake”, all vehicles would inherit this functionality and add their own functionality (such as colour or maximum speed). Now, you can instantiate lots of car and truck objects, but you will never create an object from the vehicle class as it is too general.

In these cases, it’s best to make that vehicle class an abstract class. To do so, simply use

abstract class SomeAbstractClass { code }

You can’t instantiate such a class, but you can extend it. Additionally, you can use the abstract keyword in front of methods and properties to force the extending class to define it. (This is useful if subclasses share the same method name but with slightly different functionality.)

//An abstract Item class that contains no real information (it's too general)
abstract class Item {
	abstract public $price;
	abstract public $item_id;
}

//A specific LegoItem class that is forced to define the price and item_id properties. In addition, it adds some more information to help the customer.
class LegoItem extends Item {
	public $price = 250;
	public $manufacturer = "LEGO";
	public $item_id = 1234
	public $description = "LEGO is fun for all ages! Buy it now, or buy something else. As long as you buy from our webshop.";
}

Anonymous Classes

Lastly, if you only need a simple, one-off object, you can use an anonymous class to create it. This simply means that, instead of placing a call to an existing class after the new keyword, you simply type the whole class definition.

$object = new class { public $username = "Ginty"; public $dating_profile = "Looking for a man that likes to dance."; };

echo $object->username; //Prints Ginty, as expected.

Constructors & Destructors

Constructors are very important, as they are what make every object truly unique. For example, say we’re making an online chatroom, and we create an object for every user that is currently logged in. This object would then be instantiated from the User class, which means every user would be identical – but they’re not, so how do we fix that by giving every object its own ID or username? Constructors.

Just after PHP has created a new object, it automatically makes a call to the __construct() method on that object. If you haven’t defined it, no worries, PHP just goes on with its life.

If you do define it, you can use that method to construct the object and tweak its settings. Moreover, did you ever wonder why we need parentheses after the class name when instantiating a new object (like new Class())? Well, it’s because we can pass arguments to that constructor method, just like with any function!

class User { 
	public $username; 
	public $favorite_movie;

    //BEHOLD THE POWER OF THE CONSTRUCTOR
	function __construct($usn, $movie) {
		$this->username = $usn;
		$this->favorite_movie = $movie;
	}
};

$user_1 = new User("Juan", "Inception"); //Creates a User object, and sets username and movie
echo $user_1->username; //Prints: Juan


$user_2 = new User("BATMAN", "The Dark Knight. Duh.");
echo $user_2->favorite_movie; //Prints: The Dark Knight. Duh.;

On the other hand, PHP also automatically calls the __destruct() method when an object is deleted. There’s some subtlety involved here; an object is deleted only if all references to it are gone. So, if two variables hold the reference to the same object, they both need to be deleted in order to delete the object.

class User { 
	public $username; 
	
	function __construct($usn) {
		$this->username = $usn;
	}

    //BEHOLD THE MIGHTY DESTRUCTOR
	function __destruct() {
		echo "User $this->username has been removed from chat.";
	}
};

$user_1 = new User("Juan");
unset($user_1);

//Prints: User Juan has been removed from chat.

Magic Methods

The methods from last section aren’t the only ones that are automatically called by PHP on some occasions – they are part of a larger group called the magic methods. All magic methods start with those two underscores ( __ ). (Which means that you shouldn’t use it for non-magic methods.)

Here’s a nice overview of all the other magic methods (although, the constructor is by far the most important):

Magic Method

Description

__call($name, $arg)

Is executed when you try to access inaccessible methods.
$name holds the name of the method
$arg holds an array with the arguments you provided

__callStatic($name, $arg)

Is executed when you try to access inaccessible static methods (more on that later).

__get($name)

Is executed when you try to access an inaccessible property

__set($name, $val)

Is executed when you try to set an inaccessible property.

__isset($name)

Is executed when you check if an inaccessible property is set (with the isset() function)

__unset($name)

Is executed when you delete an inaccessible property (with the unset() function)

__sleep()

Is executed just before an object is serialized (more on that later).

__wakeup()

Is executed just after an object is unserialized.

__invoke($arg1, , $argn)

Is executed when you try to call an object like a function (like $obj())

__clone()

Is executed after you’ve cloned an object

__toString()

Is executed when you try to cast an object to a string. (Basically, you can use it to define how you want the object to be cast to a string.)

__debugInfo()

Is executed when you display information about an object (with var_dump()), and returns how that information should be displayed.

__set_state($properties)

Is called when a class is exported with var_export().
$properties holds an array containing the properties that should be exported.

class User { 
	private $password = "pinkelephant"; 
	
	function __get($prop) {
		echo "Denied access to $prop. Threat has been removed.";
		
		//Reveal password only if current user is administrator
		if($current_user == "Administrator") {
			echo $this->$prop;
		}
	}

	function __clone() {
		echo "Somebody tried to clone this object.";
	}
};

$user_1 = new User();

$user_copy = clone $user_1;
//Prints: Somebody tried to clone this object (but cloning continues anyway)

$user_password = $user_copy->password;
//Prints: Denied access to password. Threat has been removed.
CONTINUE WITH THIS COURSE
Do you like my tutorials?
To keep this site running, donate some motivational food!
Crisps
(€2.00)
Chocolate Milk
(€3.50)
Pizza
(€5.00)