Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP's "use" Keyword and Autoloading

My question is in three parts:

  1. Does putting in a use statement trigger the autoloader immediately, or does it wait until the class is used? (lazy-loading)

  2. If autoloading isn't done in a lazy-load fashion, could that negatively affect performance?

  3. Which pattern is best to follow, and why? PhpStorm shows "Unnecessary fully qualified name..." as a code issue when the use statement isn't employed.

Here's an example class definition for a Laravel controller with a use statement:

namespace App\Http\Controllers;

use Carbon\Carbon;

class FooController extends Controller
{
    /**
     * This action uses the Carbon class
     */
    public function bar1()
    {
        return view('foo.bar1', ['now' => new Carbon()]);
    }

    /**
     * This action does not use the Carbon class
     */
    public function bar2()
    {
        return view('foo.bar2');
    }
}

The same class without the use statement:

namespace App\Http\Controllers;

class FooController extends Controller
{
    /**
     * This action uses the Carbon class
     */
    public function bar1()
    {
        return view('foo.bar1', ['now' => new \Carbon\Carbon()]);
    }

    /**
     * This action does not use the Carbon class
     */
    public function bar2()
    {
        return view('foo.bar2');
    }
}
like image 369
Sonny Avatar asked Apr 26 '18 13:04

Sonny


2 Answers

1) The class is autoloaded when you perform a new Class() statement.

2) see 1)

3) Which pattern is best to follow and why?:

I'd recommend to use use because you might get into a situation where you have really long namespaces and your code will become unreadable.

From the php docs:

This example attempts to load the classes MyClass1 and MyClass2 from the files MyClass1.php and MyClass2.php respectively.

<?php
spl_autoload_register(function ($class_name) {
    include $class_name . '.php';
});

$obj  = new MyClass1();
$obj2 = new MyClass2(); 
?>

Namespaces are only an additional feature to organize classes.

EDIT: As @IMSoP pointed out in the comments, new is not the only time the autoloader is triggered. Accessing a class constant, static method, or static property will also trigger it, as will running class_exists.

like image 181
Xatenev Avatar answered Oct 04 '22 00:10

Xatenev


The use statement can be thought of like a C pre-processing macro, if you're familiar with those: it rewrites the current file at compile time to let you write a short name for a long class, function, or constant name. It doesn't trigger autoloading, as it doesn't care if a class exists or not.

For instance, if you write use Foo\Bar\Baz as X, then everywhere that X is mentioned as a class name, the PHP compiler rewrites that to mention Foo\Bar\Baz instead. Only when code mentioning the class (e.g. new X, X::FOO, X::doSomething()) is actually run does it see if there really is a class Foo\Bar\Baz, and trigger the autoloader as necessary.

The common form use Foo\Bar\Baz is just shorthand for use Foo\Bar\Baz as Baz, assigning the alias Baz to the class name Foo\Bar\Baz.

As the manual points out the alias is only processed at compile time, so dynamic lookups will not use it. In the example above, class_exists('X') will return false, but you can use class_exists(X::class) to expand out the alias - the compiler will automatically substitute the full class name as a string, so at run-time, the expression will be class_exists('\Foo\Bar\Baz').

Whether use statements make your code better is therefore entirely a matter of style: the intent is that your code will be more readable without the long fully-qualified class names, but it will make no difference to how the code actually runs.

like image 28
IMSoP Avatar answered Oct 04 '22 01:10

IMSoP