🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # 类加载器 `Phalcon\Loader` 允许您根据某些预定义规则自动加载项目类。由于此组件是用C语言编写的,因此它在读取和解释外部PHP文件时提供的开销最低。 此组件的行为基于PHP的[自动加载类](http://www.php.net/manual/en/language.oop5.autoload.php)的功能。 如果在代码的任何部分中使用了尚不存在的类,则特殊处理程序将尝试加载它。 `Phalcon\Loader` 充当此操作的特殊处理程序。 通过在需要加载的基础上加载类,整体性能得以提高,因为发生的唯一文件读取是针对所需的文件。这种技术称为[延迟初始化](http://en.wikipedia.org/wiki/Lazy_initialization)。 使用此组件,您可以从其他项目或供应商加载文件,此自动加载器符合[PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md)和[PSR-4](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4.md)标准。 `Phalcon\Loader` 提供四种自动加载类选项。您可以一次使用一个或组合它们。 ## 安全层 `Phalcon\Loader` 提供默认类名称的安全层清理,避免包含未经授权的文件。请考虑以下示例: ```php <?php // 基础自动加载器 spl_autoload_register( function ($className) { $filepath = $className . '.php'; if (file_exists($filepath)) { require $filepath; } } ); ``` 上面的自动加载器缺乏任何安全性。如果函数错误地启动了自动加载器并且恶意准备的字符串被用作参数,则这将允许执行应用程序可访问的任何文件: ```php <?php // 此变量未经过筛选,来自不安全的来源 $className = '../processes/important-process'; // 检查类是否存在触发自动加载器 if (class_exists($className)) { // ... } ``` 如果 `../processes/important-process.php` 是有效文件,则外部用户可以在未经授权的情况下执行该文件。 为了避免这些或最复杂的攻击, `Phalcon\Loader` 会从类名中删除无效字符,从而降低受到攻击的可能性。 ## 注册命名空间 如果您使用命名空间或使用外部库来组织代码,则`registerNamespaces()`方法提供自动加载机制。它需要一个关联数组;键是名称空间前缀,它们的值是类所在的目录。当加载程序尝试查找类时,名称空间分隔符将被目录分隔符替换。 ```php <?php use Phalcon\Loader; // 创建自动加载器 $loader = new Loader(); // 注册命名空间 $loader->registerNamespaces( [ 'Example\Base' => 'vendor/example/base', 'Example\Adapter' => 'vendor/example/adapter', 'Example' => 'vendor/example', ] ); // 注册自动加载器 $loader->register(); // 所需的类将自动包含文件 vendor/example/adapter/Some.php $some = new \Example\Adapter\Some(); ``` ## 注册目录 第三种选择是注册可以找到类的目录。在性能方面不建议使用此选项,因为Phalcon需要在每个文件夹上执行大量文件统计信息,查找与该类名称相同的文件。按相关顺序注册目录很重要。 ```php <?php use Phalcon\Loader; // 创建自动加载器 $loader = new Loader(); // 注册目录 $loader->registerDirs( [ 'library/MyComponent', 'library/OtherComponent/Other', 'vendor/example/adapters', 'vendor/example', ] ); // 注册自动加载器 $loader->register(); // 所需的类将自动包含它所在的第一个目录中的文件,即 library/OtherComponent/Other/Some.php $some = new \Some(); ``` ## 注册类 最后一个选项是注册类名及其路径。当项目的文件夹约定不允许使用路径和类名称轻松检索文件时,此自动装带器非常有用。这是最快的自动加载方法。但是,您的应用程序越多,需要向此自动加载器添加的类/文件越多,这将有效地使类列表的维护非常麻烦,不建议这样做。 ```php <?php use Phalcon\Loader; // 创建自动加载器 $loader = new Loader(); // 注册类 $loader->registerClasses( [ 'Some' => 'library/OtherComponent/Other/Some.php', 'Example\Base' => 'vendor/example/adapters/Example/BaseClass.php', ] ); // 注册自动加载器 $loader->register(); // 要求类将自动包含它在关联数组中引用的文件,即 library/OtherComponent/Other/Some.php $some = new \Some(); ``` ## 注册文件 您还可以注册`non-classes` 的文件,因此需要一个`require`。这对于包含仅具有以下功能的文件非常有用: ```php <?php use Phalcon\Loader; // 创建自动加载器 $loader = new Loader(); // 注册文件 $loader->registerFiles( [ 'functions.php', 'arrayFunctions.php', ] ); // 注册自动加载器 $loader->register(); ``` 这些文件自动加载到 `register()` 方法中。 ## 其他文件扩展名 一些自动加载策略(如前缀,名称空间或目录)会自动将php扩展名附加到选中文件的末尾。如果您使用其他扩展,则可以使用方法`setExtensions`进行设置。按照定义的顺序检查文件: ```php <?php use Phalcon\Loader; // 创建自动加载器 $loader = new Loader(); // 设置要检查的文件扩展名 $loader->setExtensions( [ 'php', 'inc', 'phb', ] ); ``` ## 文件检查回调 您可以通过使用`setFileCheckingCallback`方法设置不同的文件检查回调方法来加速加载器。 默认行为使用`is_file`。但是,您也可以使用`null`,在加载文件之前不会检查文件是否存在,或者您可以使用比`is_file`快得多的`stream_resolve_include_path`,但如果从文件系统中删除目标文件,则会导致问题。 ```php <?php // Default behavior. $loader->setFileCheckingCallback("is_file"); // Faster than `is_file()`, but implies some issues if // the file is removed from the filesystem. $loader->setFileCheckingCallback("stream_resolve_include_path"); // Do not check file existence. $loader->setFileCheckingCallback(null); ``` ## 修改当前策略 通过将true作为第二个参数传递,可以将其他自动加载数据添加到现有值: ```php <?php // 添加更多目录 $loader->registerDirs( [ '../app/library', '../app/plugins', ], true ); ``` <a name='events'></a> ## 自动加载事件 在以下示例中,`EventsManager`正在使用类加载器,允许我们获取有关操作流程的调试信息: ```php <?php use Phalcon\Events\Event; use Phalcon\Events\Manager as EventsManager; use Phalcon\Loader; $eventsManager = new EventsManager(); $loader = new Loader(); $loader->registerNamespaces( [ 'Example\Base' => 'vendor/example/base', 'Example\Adapter' => 'vendor/example/adapter', 'Example' => 'vendor/example', ] ); // 听取所有加载的events $eventsManager->attach( 'loader:beforeCheckPath', function (Event $event, Loader $loader) { echo $loader->getCheckedPath(); } ); $loader->setEventsManager($eventsManager); $loader->register(); ``` 返回布尔值false时的某些事件可能会停止活动操作。支持以下事件: | 事件名称 | Triggered | Can stop operation? | | ------------------ | ------------------------------------------------------------------------------------------------------------------- | ------------------- | | `beforeCheckClass` | 在开始自动加载过程之前触发 | Yes | | `pathFound` | 当加载程序找到一个类时触发 | No | | `afterCheckClass` | 完成自动加载过程后触发。如果启动此事件,则自动装带器未找到类文件 | No | ## 故障排除 使用通用自动加载器时要记住的一些事项: * 自动加载过程区分大小写,类将在代码中写入时加载 * 基于名称空间/前缀的策略比目录策略更快 * 如果安装了像[APC](http://php.net/manual/en/book.apc.php) 这样的缓存字节码,这将用于检索所请求的文件(执行文件的隐式缓存)