4 minutes to read, 7.7K views since 2017.01.06 Читать на русском Читати українською

Autoloading

Including files to your scripts

When you write the program you do not write it in one file. In php you must include or require files into another by using

include 'filename.php';
require 'another.php';

If you use tons of classes in your app you need all them to be included in the header of you file. And that's going not so sweet.

Also, if you include or require some file into your script it being parsed by php even if you don't use the code from it. For example:

<?php

include_once 'some/library.php'; // SomeLibrary class

if ($userLogged) {
  $lib = new SomeLibrary();
  // do some stuff
} else {
  redirect_to('/');
}

In this script SomeLibrary would be always parsed by php and eat your memory and cpu time, even if the user is not logged and is redirected to the main page. So using a include is not always optimal decision. Of course you can include your library only in case user is logged:

<?php

if ($userLogged) {
  include_once 'some/library.php'; // SomeLibrary class
  $lib = new SomeLibrary();
  // do some stuff
} else {
  redirect_to('/');
}

Automatic including

But its not always even looks elegant. In fact, php has ability to include files automatically when they first encountered in the script if they haven't been declared yet in script.

This is done by spl_autoload_register:

spl_autoload_register(function ($class) {
    // this function would be called when php would not find some $class 
});

You should set the autoloading function above at the begining of your application initialization and forget about including files after that moment.

spl_autoload_register accepts one parameter - function which should be invoked when the some class is not found. The parameter $class of this function would be the name of the class (including namespace) that is not found:

"\Catchmetech\AutoloadingLesson\ExampleController"

If you properly generate names for your classes in system and put them in proper places then it would be no pain for you to configure the autoloader function. The best practice (PSR) says that namespaces should correspond to folders and each class should be in separate file. So, class in example above should be in folder Catchmetech\AutoloadingLesson and should be named ExampleController.php. Of course, each class should use namespaces, as i mentioned in previous lessons :)

So, how to determine what file should i include in my autoloading function? Lets str_replace the $class's namespace delimiters \ with proper to our operating system DIRECTORY_SEPARATOR:

$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';

Ok, we have a path to the file, relative path because. We should prepend to it $baseDir which should be the path of the directory where we have our application set:

$baseDir = __DIR__.'/'; 
$fileName = $baseDir.$fileName;

Also, we should check if the file we looking for really exists on the filesystem by the is_file, and if not - throw the exception:

spl_autoload_register(function ($class) {
    $base_dir = __DIR__.'/';

    $file = $base_dir . str_replace('\\',DIRECTORY_SEPARATOR, $class) . '.php';
    if (file_exists($file)) {
        require $file;
    } else {
        throw new \Exception ('can\'t include '.$file.PHP_EOL.' when trying to load `'.$class.'`');
    }
});

Voila, we have our first and simplest autoloading function created! Put the code into the top of your bootstrap file of the application and do not use include statements from now!

Read next article Working with relational database in php in course Basic PHP