Categories
PHP

Autoloading Classes

The PHP autoloading feature allows you to load class files automatically in your program. PHP calls an autoloader function when you reference a class, and the autoloader function tries to figure out which file that class is in.

This tutorial covers the following topics:

  1. What is autoloading
  2. What is autoloader
  3. Why use an autoloader
  4. PHP __autoload() function
  5. PHP spl_autoload_register() function
  6. PHP registering multiple autoloader functions
  7. Autoloading classes based on namespace structure

What is autoloading

Autoloading is the process of automatically loading PHP classes without explicitly loading them with the require(), require_once(), include(), or include_once() functions.

To autoload classes, you must follow two rules:

  1. Each class must be defined in a separate file.
  2. Name your class files the same as your classes. The class Views would be placed in Views.php, a class called Users would be stored in Users.php and so on.

When you use the statement new ClassName(), if the class ClassName doesn’t exist (because it hasn’t been included), PHP trigger an autoloader that can then load the file ClassName.php, and the rest of the script will continue as normal without requiring to manually write the line require 'ClassName.php';.

What is autoloader

An autoloader is a function that takes a class name as an argument and then includes the file that contains the corresponding class. The following example demonstrates how you can make an autoloader function to load classes:

<?php
 function my_autoloader ( $class ) {
  $path = $_SERVER['DOCUMENT_ROOT'] . '/classes/';
  require $path . $class .'.php'; 
 }

To implement an autoloader, PHP provides two functions:

  1. __autoload(), not recommended, deprecated as of PHP 7.2 and removed as of PHP 8.0.
  2. spl_autoload_register(), recommended.

Why use an autoloader

How often have you seen code like this at the top of your PHP files?

<?php
 require 'file_1.php';
 require 'file_2.php';
 require 'file_3.php';

All too often, right? The require(), require_once(), include(), and include_once() functions load an external PHP file into the current script, and they work wonderfully if you have only a few PHP scripts.

However, what if you need to include a hundred PHP scripts? The require() and include() functions do not scale well, and this is why PHP autoloaders are important. An autoloader is a strategy for finding a PHP class, interface, or trait and loading it into the PHP interpreter on-demand at run-time, without explicitly including files.

__autoload() magic function

Note: The usage of __autoload function is not recommended, it has been DEPRECATED as of PHP 7.2.0, and REMOVED as of PHP 8.0.0.

__autoload(), a magic function, is automatically invoked by the PHP when we instantiate a class that has not already been loaded. For example:

<?php
 function __autoload($class) {
  $path = $_SERVER['DOCUMENT_ROOT'] . '/classes/';
  require_once  $path . $class .'.php';
 }
 
 $object = new myClass();
 # Loads the class stored in "/classes/myClass.php"

As of PHP 7.2.0 the __autoload() function has been deprecated and removed since PHP 8.0.0. Now it is recommended to use the spl_autoload_register for that purpose instead.

spl_autoload_register()

PHP 5.1.2 introduced the more flexible spl_autoload_register() function in its SPL library which allows you to register multiple autoloader functions.

Example: spl_autoload_register() as a replacement for the __autoload() function:

<?php
 spl_autoload_register( function($class) {
  $path = $_SERVER['DOCUMENT_ROOT'] . '/classes/';
  require_once  $path . $class .'.php';
 });
 
 $object = new Home();
 # Loads the class "/classes/Home.php"
 
 $object = new Template();
 # Loads the class "/classes/Template.php"

Registering multiple autoloader functions for each namespace

The spl_autoload_register() allows to create an autoload chain, a series of functions that can be called to try and load a class or interface:

<?php
 spl_autoload_register (function ($class) {
  // for BrainBell namespace
  require 'path/to/brainbell/classname.php';
 });

 spl_autoload_register(function ($class) {
  // for Views namespace
  require 'path/to/views/classname.php';
 });

Example: autoloader.php, following is the expanded version of the above code:

<?php
 # File name: autoloader.php
 # Registering for Views namespace
 spl_autoload_register(function ($class) {
  $prefix = 'Views\\'; # namespace prefix
  $len = strlen($prefix);

  if (strncmp($prefix, $class, $len) !== 0)
   return; # move to the next registered autoloader

  $relative_class = substr($class, $len);
  
  # define class files directory
  $base_dir = __DIR__ . '/classes/views/'; 
  $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
  
  if (file_exists($file)) {
   require $file;
  }
 });

 # Registering autoloader for BrainBell namespace
 spl_autoload_register(function ($class) {
  $prefix = 'BrainBell\\';
  $base_dir = __DIR__ . '/classes/brainbell/';
  $len = strlen($prefix);
  if (strncmp($prefix, $class, $len) !== 0) {
   return;
  }
  $relative_class = substr($class, $len);
  $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
  if (file_exists($file)) {
   require $file;
  }
 });

The above example is taken from https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md.

To see if the above autoloader is working properly, create two classes BrainBell\Template and Views\Template and save them in the directory classes/brainbell/ and classes/views/ respectively.

The classes/brainbell/Template.php file:

<?php
 # File name: classes/brainbell/Template.php
 namespace BrainBell;
 class Template {
  private $message;
  function __construct() {
   $this->message = __ClASS__;
  }
  function getMessage() {
   return $this->message;
  }
  function getPath() {
   return __DIR__;
  }
 }

The classes/view/Template.php file:

# File name: classes/view/Template.php
 namespace Views;
 class Template {
  private $message;
  function __construct() {
   $this->message = __ClASS__;
  }
  function getMessage() {
   return $this->message;
  }
  function getPath() {
   return __DIR__;
  }
 }

Next, include the autoloader.php in the script and reference the above classes:

<?php
 # File name: example.php
 require_once 'autoloader.php';

 // Loading classes from BrainBell namespace
 $class = new BrainBell\Template();
 echo $class->getMessage().'<br>'; # BrainBell\Template
 echo $class->getPath().'<br>';    # D:\xampp\htdocs\classes\brainbell

 // Loading classes from Views namespace 
 $class = new Views\Template();
 echo $class->getMessage().'<br>'; # Views\Template
 echo $class->getPath();           # D:\xampp\htdocs\classes\views

Autoloading classes based on namespace structure

PHP can autoload classes without needing an autoloader function if the directory structure containing the classes matches the namespaces of the classes.

In the following example, the spl_autoload_register() tries to figure out the class files relative to the current directory path. So if your script (example.php) is saved in the www directory, it tries to load the views\home() class from the www/views/home.php path:

<?php
 # /www/example.php

 spl_autoload_register();

 $home = new classes\home();
 # Loads /www/classes/home.php

 $home = new views\home();
 # Loads /www/views/home.php

Follow these instruction for the complete example:

  1. Create directories/folders on your document root: classes, views and models.
  2. Create two PHP files in each folder: home.php and all.php.
  3. Create classes by writing the following code in each file:

classes/home.php

<?php
namespace classes;
class home {
 public function get(){
  return 'classes/home.php';
 }
}

classes/all.php

<?php
namespace classes;
class all {
 public function get(){
  return 'classes/all.php';
 }
}

models/home.php

<?php
namespace models;
class home {
 public function get(){
  return 'models/home.php';
 }
}

models/all.php

<?php
namespace models;
class all {
 public function get(){
  return 'models/all.php';
 }
}

views/home.php

<?php
namespace views;
class home {
 public function get(){
  return 'views/home.php';
 }
}

classes/all.php

<?php
namespace views;
class all {
 public function get(){
  return 'views/all.php';
 }
}
  1. Create a file loader.php at document root and write the following code:
<?php

spl_autoload_register();
$home = new classes\home();
echo $home->get() . <br>;

$home = new views\home();
echo $home->get(). <br>;

$home = new models\home();
echo $home->get(). <br>;

$all = new classes\all();
echo $all->get(). <br>;

$all = new views\all();
echo $all->get(). <br>;

$all = new models\all();
echo $all->get();

/*Output:
classes/home.php
views/home.php
models/home.php
classes/all.php
views/all.php
models/all.php*/

You can see all classes loaded without using the include or require keywords. Since PHP 5.3, you can use spl_autoload_register() with namespaces, which means that you can organize your project and autoload your PHP classes without the require or include keyword.


PHP OOP Tutorials: