PHP“使用”关键字和自动加载

Posted

技术标签:

【中文标题】PHP“使用”关键字和自动加载【英文标题】:PHP's "use" Keyword and Autoloading 【发布时间】:2021-08-21 13:04:55 【问题描述】:

我的问题分为三个部分:

    放入use 语句会立即触发自动加载器,还是等到使用该类? (延迟加载)

    如果自动加载不是以延迟加载方式完成的,会不会对性能产生负面影响?

    最好遵循哪种模式,为什么?当未使用 use 语句时,phpStorm 将“不必要的完全限定名称...”显示为代码问题。

这是一个带有use 语句的 Laravel 控制器的示例类定义:

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');
    

没有use声明的同一个类:

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');
    

【问题讨论】:

【参考方案1】:

1) 当您执行new Class() 语句时,该类会自动加载。

2) 见 1)

3) 最好遵循哪种模式以及为什么?:

我建议使用use,因为您可能会遇到这样一种情况,即您的命名空间非常长并且您的代码将变得不可读。

来自php docs:

此示例尝试从以下位置加载类 MyClass1 和 MyClass2 分别是 MyClass1.php 和 MyClass2.php 文件。

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

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

命名空间只是组织类的附加功能。

编辑:正如@IMSoP 在 cmets 中指出的那样,new 并不是唯一一次触发自动加载器。访问class constant、static method 或static property 也会触发它,运行class_exists 也会触发它。

【讨论】:

这是官方文档中的某处吗? @Sonny 我已经编辑了我的答案。如您所见,在示例中它甚至没有使用use。那是因为命名空间与自动加载本身无关。命名空间是组织类的附加功能。 请注意new 并不是自动加载器运行的唯一时间。访问类常量、静态方法或静态属性也会触发它,运行 class_exists 也会触发它。【参考方案2】:

use statement 可以被认为是一个 C 预处理宏,如果您熟悉这些:它会在编译时重写当前文件,以便您为长类、函数或常量名。它不会触发自动加载,因为它不关心一个类是否存在。

例如,如果您编写use Foo\Bar\Baz as X,那么在任何地方提到X 作为类名,PHP 编译器都会重写它以提及Foo\Bar\Baz。只有当提到类的代码(例如new XX::FOOX::doSomething())实际运行时,它才会查看是否真的有一个类Foo\Bar\Baz,并在必要时触发自动加载器。

常见的形式use Foo\Bar\Baz 只是use Foo\Bar\Baz as Baz 的简写,将别名Baz 分配给类名Foo\Bar\Baz

由于the manual points out 别名仅在编译时处理,因此动态查找不会使用它。在上面的示例中,class_exists('X') 将返回 false,但您可以使用 class_exists(X::class) 扩展别名 - 编译器会自动将完整的类名替换为字符串,因此在运行时,表达式将为 @987654337 @。

use 语句是否让你的代码更好因此完全是一个风格问题:目的是你的代码在没有长的完全限定的类名的情况下将更具可读性,但这对代码的实际表现没有影响运行。

【讨论】:

以上是关于PHP“使用”关键字和自动加载的主要内容,如果未能解决你的问题,请参考以下文章

浅析PHP类的自动加载和命名空间

PHP的类自动加载机制

PHP面向对象——Final关键字 类的自动加载

final关键字, 自动加载类

Final关键字和类的自动加载

PHP - 重置自动加载和声明的类