evo / autoloader
PSR4 兼容的自动加载器
Requires
- php: >=5.6
This package is not auto-updated.
Last update: 2024-09-26 05:33:07 UTC
README
PSR4 兼容的自动加载器
尽管我尝试使用 Composer 来处理所有与自动加载相关的事情。
有时您需要在 Composer 之外使用自动加载器。可能是因为一个小型项目等...
use evo\autoloader\Autoloader;
require_once 'src/evo/autoloader/Autoloader.php';
$Autoloader = Autoloader::getInstance();
默认情况下,自动加载器在其放置的位置注册一个空命名空间。
$Autoloader->registerPath('', '');
这是除 getInstance() 方法之外最重要的方法。它定义如下:
registerPath($namespace, $path, [$priority = 100])
其中 $namespace 是一个命名空间,例如 evo\\autoloader,而路径是一个路径,如 __DIR__.'/scr/evo/'。在大多数情况下,自动加载器会考虑到这些差异,例如,对于命名空间使用 \\evo\\autoloader\\,而对于路径使用 __DIR__.'/scr/evo'。您可以使用相对路径或绝对路径与自动加载器一起使用。$priority 将注册的路径按升序排序,并按命名空间分组。因此,优先级较低的路径将首先在具有多个路径的命名空间中调用。
让我们回到默认设置,这是一个没有命名空间、没有路径的设置。因此,它将基于调用其正在尝试加载的类的路径进行根目录设置。解释它如何确定路径的最简单方法是,它会在 registerPaths 中搜索 $namespace,然后为该命名空间添加 $path + class info。
现在假设这个文件不是 README.md,而是 index.php。在这个相同的文件夹中,我们有一个简单的类,如下所示:
//location /
class A
{
}
仅使用默认设置,这个类就可以被加载。自动加载器会查找命名空间,找到 '' 空值,然后添加空路径和类名 A.php,我们得到相对于 index.php 所在文件夹的相对路径,并且没有命名空间,我们只需查找文件名即可找到。
现在让我们尝试更多示例
//location /src/evo/
namespace src\evo;
class B
{
}
像类 A 一样,这个类也可以很好地加载。让我们计算路径,记住我们在 registerPath 中为两个参数都使用了 '',这是默认注册的路径。和第一个例子一样,我们再次找到当前位置,并添加命名空间和类名,这得出 /src/evo/B.php。您可能认为自动加载器会根据命名空间搜索 registerPath,我毕竟是这样说的,但我们从未注册过 src\evo 命名空间和路径。幸运的是,自动加载器足够智能,如果在给定命名空间找不到路径,它会根据类提供的命名空间回溯。它从 registerPath 中的 src\evo 开始查找,但没有找到。然后它删除一个段并查找 src,同样没有找到。最后,它删除最后一个段并查找 '',这是我们默认注册的。然后它为该命名空间取路径,并添加类的命名空间和类名。对于这个路径,它得出 /src/evo/B.php,这是正确的。
让我们看看一个无法使用默认设置加载的类
//location /src/evo/
namespace evo;
class C
{
}
这里我们缺少命名空间中的 src 部分,并且它没有在路径中得到考虑。在这种情况下,自动加载器将找不到要加载的文件。原因应该是显而易见的。自动加载器找不到命名空间,因此它会像上面描述的那样使用默认设置,然后添加类的信息。这得出 /evo/C.php,但我们位于 src 文件夹之上,因此该文件夹从自动加载器的计算中缺失。幸运的是,我们可以注册我们需要的任意数量的命名空间/路径对,并且注册此路径的方法很简单:
$Autoloader->registerPath('', __DIR__.'/src');
现在当我们把参数和类信息加起来时,我们得到这个 src + evo + C.php 或 src/evo/C.php,这正是我们需要的。
好的,我们几乎完全没触碰命名空间参数,就已经取得了很大的进展。上面的类也可以这样注册:
$Autoloader->registerPath('evo', __DIR__.'/src/evo');
这也将正确解析文件的路径。它是通过这种方式解析的:自动加载器查找命名空间 evo,它在 __DIR__.'/src/evo' 的路径中找到它。现在因为它找到了类命名空间中的 evo 部分,所以它不会把这个加到路径中,在这种情况下命名空间中没有剩下任何内容,所以它只加上类名,我们最终得到 __DIR__.'/src/evo/C.php。这本质上和上面的例子是一样的。
在上面的例子中,自动加载器需要做的功比上一个例子要少一点,所以你可能会通过以这种方式注册命名空间获得一点性能提升。但说到底,这种方法真正的优势在于类位于与命名空间没有逻辑关系的路径时。例如:
//location /src/evo/
namespace foo\bar;
class D
{
}
如你所见,命名空间 foo\bar 与路径 src/evo 完全不匹配。不那么灵活的自动加载器可能会放弃这个配置,但我们可以通过使用这个命名空间/路径对来很好地处理这个问题。
$Autoloader->registerPath('foo\bar', __DIR__.'/src/evo');
和前面的例子(第二个例子中的类 C)一样,自动加载器在我们的 registerPaths 中查找命名空间,并找到上面的路径 __DIR__.'/src/evo',然后因为整个命名空间都被找到了,所以它只加上类名,得到 __DIR__.'/src/evo/D.php',这正是类所在的位置。
我们最后需要讨论的是为同一个命名空间设置多个路径,是的,这是可能的。
$Autoloader->registerPath('foo\bar', __DIR__.'/src/evo');
$Autoloader->registerPath('foo\bar', __DIR__.'/foo/bar');
现在当自动加载器找到命名空间时,它将遍历这些路径。
希望这些例子能解释清楚自动加载器的工作方式。还有一些其他的方法我想提及。首先是调试方法。这很重要,因为自动加载有时候可能会很困难。另一个挑战是自动加载器做了很多事情,所以只是打印东西出来可能会输出太多信息,变得毫无价值。让我们看看调试方法及其用法。
$Autoloader = Autoloader::getInstance();
$Autoloader->setDebug(true);
new C();
$Autoloader->setDebug(false);
由于自动加载器是单例的,我们可以调用 getInstance 并获取之前创建的相同类的实例。这无论从哪里调用都是正确的。我们不需要有多个这样的自动加载器的实例。调试方法相当简单,它接受一个布尔值 true 或 false。true 打开输出,false 关闭输出。所以在这里,我们在调用我们遇到问题的类时打开输出,然后关闭输出。这可以防止自动加载器输出过多的信息。
在这个例子中,我们将使用我们最初无法加载的类 C,调试输出看起来像这样:
============================ evo\autoloader\Autoloader::debug ============================
evo\autoloader\Autoloader::splAutoload evo\C
Checking class: C
Checking namespace: evo
checking pathname:/evo/C.php
==========================================================================================
现在我们将看看同一个类,但第二个例子中,我们通过注册命名空间与路径来加载类
============================ evo\autoloader\Autoloader::debug ============================
evo\autoloader\Autoloader::splAutoload evo\C
Checking class: C
Checking namespace: evo
checking pathname:/evo/src/C.php
Found: /evo/src/C.php
==========================================================================================
如果你比较这两个,你会注意到第一个没有 Found: 部分,这仅仅表示文件找到的位置。如果它必须遍历 registerPaths 和命名空间,就像上面描述的那样,还可能有多个 checking pathname: 条目。
大多数其他方法应该都是相当容易理解的,所以下面你可以找到所有公共方法列表。
//Get the autoloader instance
public static function getInstance($throw = false, $prepend = false)
//set debug (covered above)
public function setDebug($debug = false)
//called whenever a class is loaded, has to be public but not really intended for use
public function splAutoload($class)
//register a namespace path pair
public function getRegisteredPaths($namespace = null)
//register a namespace path pair (covered above)
public function registerPath($namespace, $path, $priority = self::DEFAULT_PRIORITY)
//remove a path that was registered, you can remove a whole namespace or a path within the namespace
public function unloadPath($namespace, $path = null)
//check if a namespace is registered
public function isRegistered($namespace, $path = null)
//get the path that a class was found at, null get all classes and their paths
public function getLoadedFile($class = null);
享受吧