PHP OOP

PHP OOP Autoloading

PHP OOP Autoloading

Autoloading allows you to automatically include the class files.

Why Autoloading?

The more clean and clear your code is the more readable and useful it is. When you are working in a quite large PHP project, you will have a large number of class files. In each PHP file, you will need to have a bunch of include or require statements at the beginning to use those classes.


<?php
include 'Class1.php';
include 'Class2.php';
include 'Namespace\Class1.php';
include 'Namespace\Class2.php';
// and more...

This is not the way we need it to be done. It would be great if we could let PHP to automatically load (autoload) the class files for us. PHP supports autoloading with a little piece of coding.

Usage of Autoloading in PHP

Let’s assume that we have the following files. Circle.php and Square.php are two class files while usage.php is the file which we are going to use those classes in.


Circle.php
Square.php
usage.php

Now, we need to access the Circle and Square classes which are in Circle.php and Square.php respectively.

Before that, we need the autoloader to be in a separate file. Therefore, we can use the autoloader in multiple PHP files. Let’s create autoload.php in the root and add the autoloader into that file.

PHP’s in-built spl_autoload_register function is used to register an autoloader.

autoload.php


<?php
spl_autoload_register(function($className) {
	$file = $className . '.php';
	if (file_exists($file)) {
		include $file;
	}
});

Now, all we have to do is to include autoload.php in any file we are going to access the classes.

usage.php


<?php
include 'autoload.php';

$circle = new Circle;
$square = new Square;

The Logic of Autoloading

Let’s understand what was going on with the autoloader in 3 steps.

Step 1: Registering an Autoloader

  • You know, PHP has numerous in-built functions. spl_autoload_register is one of them. It accepts 3 parameters, but we will only use the first one here.
  • We will call the spl_autoload_register() function with a callback (anonymous function).
  • You can call that function multiple times with different callback functions.
  • PHP remembers all of those callback functions in order. This is called Registering autoloaders.

Step 2: Running the Autoloader

  • When you try to access a class in your code (new Circle() above), PHP first checks if the class is found.
  • If the class was not found, PHP tries to find it. PHP does it using registered autoloaders. If there are registered autoloaders, PHP will run the first registered autoloader. After running it, PHP will check if the class is now found. If not, PHP will run all the registered autoloaders by the registered order.
  • If PHP founds the class, it will terminate the “finding process” and the other autoloaders are not called.

Step 3: What happened in the last example?

  • Here’s our autoloader from the last example.
    
    <?php
    spl_autoload_register(function($className) {
    	$file = $className . '.php';
    	if (file_exists($file)) {
    		include $file;
    	}
    });
    
    
  • When PHP calls the callback function, it sends the class name as the first argument. ($className in the callback function)
  • Let’s assume that $className was Circle. We know, the Circle class is in the Circle.php file.
  • If the file Circle.php exists, we will include it. Now, the Circle class is available in our PHP file.
It is better to not to throw errors if the file is not found, as there may be multiple autoloaders to find the file.

Namespace-Friendly Autoloading

In the namespaces chapter, we learned how to namespace classes and map them with the folder structure.

Mapping Namespaces and Classes
Mapping Namespaces and Classes

The autoloader we created above is neither namespace-friendly nor works in PHP files which are not in the root directory. Here’s the improved autoloader!


<?php
spl_autoload_register(function($className) {
	$file = __DIR__ . '\\' . $className . '.php';
	$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
	if (file_exists($file)) {
		include $file;
	}
});

  • __DIR__ confirms that the path starts from the folder where autoload.php is in.
  • Then, we replace \ to DIRECTORY_SEPARATOR.

These two steps confirm that our autoloader is namespace friendly. This autoloader assumes that the autoload.php (or whatever name you use) is in the root directory.

If the autoload file is not in the root directory, there are some ways to go to the root folder.

  • If it is in /folder/ you have to go one folder back. Here are the ways.
    
    <?php
    // one folder back
    $root = __DIR__ . '\\..\\'; 
    $root = $_SERVER['DOCUMENT_ROOT'];
    $root = dirname(__DIR__);
    
    			
  • If it is in /folder/subfolder/ you can extend the above code.
    
    <?php
    // two folders back
    $root = __DIR__ . '\\..\\..\\'; 
    $root = $_SERVER['DOCUMENT_ROOT'];
    $root = dirname(dirname(__DIR__));
    
    			

Reminder: $_SERVER[‘DOCUMENT_ROOT’] is the root set by your web server. See Superglobals. And, \\ represents \ inside quotes. See Strings.

Example Autoloading

Structure


src/
	Fruits/
		Apple.php
		Orange.php
		Banana.php
	App.php
includes/
	autoload.php
app.php

includes/autoload.php


<?php
spl_autoload_register(function($className) {
	$file = dirname(__DIR__) . '\\src\\' . $className . '.php';
	$file = str_replace('\\', DIRECTORY_SEPARATOR, $file);
	echo $file;
	if (file_exists($file)) {
		include $file;
	}
});

In this time, autoload.php is in the includes folder. We have to search for the class files in the src folder.

app.php


<?php
// app.php
include_once 'includes/autoload.php';

// freely use the classes
$app = new App();
$apple = new Fruits\Apple();
$orange = new Fruits\Orange();
$banana = new Fruits\Banana();


Project-Specific Autoloading

Sometimes, we declare an autoloader to autoload only the classes which are under a project. This is called “Project-Specific” autoloading. The below autoloader will only include the classes which are prefixed with Hyvor\Developer.


<?php
spl_autoload_register(function ($class) {
    // namespace prefix
    $prefix = 'Hyvor\\Developer\\';

    // check if this is a class from our project
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0)
        return; // nope, it isn't

    // get the relative class name
    // remove the namespace name
    $className = substr($class, $len);

    // base directory of classes
    $baseDir = __DIR__ . '/src/';
    // relative including
    $file = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php';

    // if the file exists, require it
    if (file_exists($file)) {
        require $file;
    }
});

Conclusion

In this chapter, you learned how to create a PHP autoloader to automatically include your class files. Nowadays, most PHP developers use a tool called Composer for autoloading which we do not cover in this tutorial. But, if you are working on a large project which depends on many PHP libraries from other developers, you may check out Composer and learn how to use it.

Leave a Reply

Your email address will not be published. Required fields are marked *

Close