Auto Load of classes in PHP

Asked

Viewed 1,608 times

2

I’m developing a mini-framework to use in my applications and did auto load classes in this way :

function __autoload($Class) {

    $cDir = ['Conn', 'Helpers', 'Models'];
    $iDir = null;

    foreach ($cDir as $dirName):
        if (!$iDir && file_exists(__DIR__ . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR . $Class . '.class.php') && !is_dir(__DIR__ . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR . $Class . '.class.php')):
            include_once (__DIR__ . DIRECTORY_SEPARATOR . $dirName . DIRECTORY_SEPARATOR . $Class . '.class.php');
            $iDir = true;
        endif;
    endforeach;

    if (!$iDir):
        trigger_error("Não foi possível incluir {$Class}.class.php", E_USER_ERROR);
        die;
    endif;

}

There is how to optimize more this code?

3 answers

4


You can do as follows, first improving the readability of the code, using simpler names to make it easier to understand and using the normal syntax of if and foreach.

Then using the function spl_autoload_register to the infinites of the magical method __autoload, because using the function spl_autoload_register, you have the possibility to register more than one autoload function for your classes.

Remembering also that the magical method __autoload, may no longer exist in future versions of PHP, as this function is obsolete according to its documentation.

<?php

// AUTO LOAD DE CLASSES ####################
function myAutoload($className) {

    $directoryNames = ['Conn', 'Helpers', 'Models'];
    $includedClass = false;

    foreach ($directoryNames as $directoryName) {

        $path = __DIR__ . DIRECTORY_SEPARATOR . $directoryName . DIRECTORY_SEPARATOR . $className . '.class.php';

        if (!$directoryName && file_exists($path) && !is_dir($path)) {

            include_once ($path);
            $includedClass = true;

        };

    }

    if (!$includedClass) {
        trigger_error("Não foi possível incluir {$className}.class.php", E_USER_ERROR);
        die;
    }

}

//Usando essa função você pode usar mais de uma função para autoload.
spl_autoload_register("myAutoload");

You also when creating your own autoload function, you could use an already ready specification which is the PSR-4 for class loads in PHP.

3

You can optimize by eliminating the technique that iterates an array of directories.

$cDir = array('pasta1', 'pasta2', 'pasta3')
foreach ($cDir as $dirName) {
    // aqui vai repetir, buscando nos diretórios registrados até encontrar.
    // isso é redundante e pode ser evitado
}

A suggestion is to standardize according to recommendations from php-fig.org.
You must have seen somewhere something like PHP PSR, PSR4, etc.
PSR stands for -> PHP Standards Recommendation.
It is not a rule that everyone should follow. It is optional.

Optimizing with PSR4

To optimize your autoload, you could do something in the PSR4 standard:

spl_autoload_register(function ($class) {

    // project-specific namespace prefix
    $prefix = 'Foo\\Bar\\';

    // base directory for the namespace prefix
    $base_dir = __DIR__ . '/src/';

    // does the class use the namespace prefix?
    $len = strlen($prefix);
    if (strncmp($prefix, $class, $len) !== 0) {
        // no, move to the next registered autoloader
        return;
    }

    // get the relative class name
    $relative_class = substr($class, $len);

    // replace the namespace prefix with the base directory, replace namespace
    // separators with directory separators in the relative class name, append
    // with .php
    $file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';

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

That’s all it is. The only thing you would modify is your namespace prefix and the file base.

$prefix = 'Foo\\Bar\\';

If your namespace is Qualquer\Outro\Nome, would look like this

$prefix = 'Qualquer\\Outro\\Nome\\';

The basis of the files is defined in this section

$base_dir = __DIR__ . '/src/';

Just configure the base according to your project.

Obviously you will have to use namespace in your files that you want to autocharge.

The nomenclature of directories and files must follow the same pattern as the class name.

Example, when instantiating a class:

new \Foo\Bar\Baz\Qux;

autoload, from the above example, will recognize the chunk of the namespace prefix: \Foo\Bar and will work with the rest Baz\Qux

Thus forming the location of the file

/www/site/src/Baz/Qux.php

This logic eliminates all that iteration cost of an array to traverse directories that is mostly unnecessary and still runs the risk of colliding with an equal name in different directories.

This array technique was useful for a time when PHP did not yet have the namespaces, available from PHP5.3.

Related to the namespace: How namespaces work in PHP?

-1

                $pastas = ['dir1', 'dir2', 'dir3'];
                foreach($diretorios as $pacth)
                {
                    foreach(glob("asset/$pacth/*.class.php") as $filename){
                    require_once $filename;
                }
            }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.