Functions autoloading in PHP

Estándar

Please excuse me for the typos, but I’m a Spanish-speaking person.

Intro

A few days ago I was seeing news of PHP 5.3 (too late, I know), and I saw some that I thought were important: namespaces and classes autoloading.

On these two issues I thought to investigate how to remake my old projects, in order to reduce the amount of code lines occupying the file import statements.

As usual, I usually create a class MyClass in a file MyClass.php, and a function my_function in a file my_function.php, making me life easy to recognize at first glance what that file is and getting an understandable and organized project.

What I’m trying to say? In this article I will use a similar file structure, in order to assist in the organization and see how using namespaces and classes autoloading can be much easier to do our work as PHP programmers.

But why the title says functions autoloading if you’re going to teach me classes autoloading? Well, because we are going to use classes autoloading and apply it to load functions through a class.

Hands on!

Now that you have more or less a vision of what is to be done, let’s start with the code.

fs-afnThe next image shows the file system structure that I will use throughout the article. Show as a picture facilitates our understanding, avoiding mistakes then.
As we can see, we have a main file index.php, in which we will carry out the tests. All PHP code required in this article is located within php folder, and as you might guess, inside it will be our classes, functions, and helpers folder haves the PHP script that will allow us to make functions autoloading.

I will start to show code for each file, to see the why I organized them in such manner.

<?php

namespace php\classes;
use php\helpers\Fn;

class Class1 {
    
    public $msg = "Hello, I'm first class.";
    
    public function say() {
        Fn::say($this->msg);
    }
    
}

?>
<?php

namespace php\classes;

class Class2 extends Class1 {
    
    public function __construct() {
        $this->msg = "Hi, I'm second class.";
    }
    
}

?>
<?php

namespace php\functions;

function say($var) {
    if (is_string($var) || is_numeric($var)) {
        echo $var;
    } elseif (is_bool($var)) {
        echo $var ? 'true' : 'false';
    } elseif (is_object($var) && method_exists($var, '__toString')) {
        // echo $var->__toString();
    } elseif (is_array($var)) {
        $s = array();
        foreach ($var as $k => $v) {
            $s[] = $k . ' = ' . $v;
        }
        echo implode('&', $s);
    } elseif (is_null($var)) {
        echo 'null';
    }
}

?>
<?php

namespace php\helpers;

/**
 * Autoloading functions in PHP.
 * 
 * @author Bryan Horna <bryanjhv@gmail.com>
 * @version 0.2
 */
class Fn {
    
    private function __construct() {}
    private function __wakeup() {}
    private function __clone() {}
    
    public static function __callStatic($fname, $args) {
        if (!function_exists($fn)) {
            $fn = "php\\functions\\$fn";
            require str_replace('\\', '/', $fn) . '.php';
        }
        return call_user_func_array($fn, $args);
    }
    
}

?>
<?php

# include_once 'php/autoload.php';
spl_autoload_register();

use php\helpers\Fn;
use php\classes\Class2;

# Using the created class
(new Class2())->say();

# Custom functions
Fn::say("Hello, world!");

# PHP built-in functions
echo Fn::str_replace(" ", "", "This is a text.");

?>

Am I missing something? Ah, yes, sorry. I forgot to include the code of php/autoload.php, but do you need that file? It’s not, but if you want to complicate things, you can create it and write <?php spl_autoload_register(); ?> and ready.

Code explanation

Now I will explain the code, but only the parts that are neccessary to explain. I.e., do not explain how inheritance works in PHP, just explain why the simplicity of the code.

  • Namespaces: Namespaces in PHP were introduced in PHP 5.3, and like that in other programming languages, they act encapsulating the code we have in "packages". You can find lots of info on the Internet about it.
  • Classes autoloading: The class autoloading is available in PHP since version 5.1.2 (the spl_autoload_register function). But the good news say that when we work with namespaces equal to our filesystem structure, becomes useless to create an autoload function, because PHP does this process automatically.
  • Fn class: This class will help us to dynamically load functions. The only change we make in our code is to add Fn:: before the call to one of our defined functions. Then I made __construct, __wakeup and __clone because they wouldn’t be needed in the class that we created. Moreover, the __callStatic method does it all.

Now, the million-dollar question: and what would help me this? Well, I tell you what I did with this. "I was doing a users system, when suddenly it ocurred to me to use sha1 and md5 to encrypt user passwords. When I gave a look at the PHP site, I realized that I should not use these functions for that. I thought: what do I then need? When I see the PHP site, there is a nice function called password_hash, which does this job for you. There are other functions that help this. If you clicked the link above, you’ll see that it was introduced in PHP 5.5, and my server does not have that version, haves PHP 5.4. I looked for a polyfill which convinced me. But how do you know if password_hash is in the PHP version you are using, because I don’t want to make a version check and also be checking if it exists whenever you need it. It was there where I decided to make Fn::password_hash and ready! If I run it in PHP 5.4, it will call the polyfill; if it is PHP 5.5 it will call PHP 5.5’s built-in function.".

I hope this has been helpful. As always, you can download the code used from here, and if you have any doubts, do not forget to comment in order to resolve them. Happy coding!

Anuncios

¿Y tú qué opinas?

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s