Laravel Real-Time Facades 内部实现机制的分解

我已经很久没有写过技术文章了。我刚查过,已经一年多了!¯_(ツ)_/¯

我从来没有那么忙过,但在我能用文字写作的同时,我却学不到任何新东西。我宁愿在其他文章中解释我在那几个月里所做的事情。让我们看一看今天的文章。

Real-Time Facades

Laravel的 Real-Time facades 可以像处理facade一样处理常规类,而无需定义facade类。但如果你不熟悉facade,那么你可以看看下面的文章,我相信你会了解Laravel的facade,以及如何创建自己的外观。

Real-time 门面代理就像魔术方法一样,要了解魔术,你需要了解自动加载类在 PHP 中是如何工作的。

自动加载类

在编写 PHP 应用程序时,一开始文件的数量很少。可以使用 include require 表达式来引用类文件。 但是随着项目的增长,类也会增长,并且编写 require 表达式来加载这些文件没有任何意义。在这种情况下,你应该使用 SPL 自动加载。有没有想过为什么我们在使用 composer 时在我们的脚本中需要 vendor/autoload.php? 如果你以前从未想过,让我告诉你,它会为我们自动加载文件。

现在,让我们动手吧!这就是我们项目简单的样子。

项目结构

  • app 目录包含 App 类。
  • src 目录包含Source 类。
  • 基础/工作目录包含 Current 类。

Current 类扩展了 Source 类,Source 类扩展了 App 类。 查看以下代码库。 只是几个简单的类。

现在,要实例化 Current 类,我们需要该文件以及相关文件。 在不使用 SPL 自动加载时,我们的 index.php 应该如下所示。

<?php

require './app/App.php';
require './src/Source.php';
require './Current.php';

echo (new Current())->sayHello('anik');

这里,require 表达式的顺序很重要。除此以外,以任何顺序交换第 3、4、5 行都不起作用。因此,你必须要注意类的导入顺序。

现在,让我们看看下面的例子。

<?php

function autoload_src($file): bool
{
    echo sprintf('autoload_src: Looking for "%s".%s', $file, PHP_EOL);

    if (strtolower(($extract = explode('\\', $file))[0]) === 'source') {
        return loadFileIfExists('./src', $extract[1] ?? '');
    }

    return false;
}

function autoload_app($file): bool
{
    echo sprintf('autoload_app: looking for "%s".%s', $file, PHP_EOL);

    if (strtolower(($extract = explode('\\', $file))[0]) === 'app') {
        return loadFileIfExists('./app', $extract[1] ?? '');
    }

    return false;
}

function autoload_current($file): bool
{
    echo sprintf('autoload_current: looking for "%s".%s', $file, PHP_EOL);

    return loadFileIfExists('.', $file);
}

function loadFileIfExists(string $directory, string $filename): bool
{
    if (file_exists($path = sprintf('%s/%s.php', rtrim($directory, '/'), $filename))) {
        include($path);

        return true;
    }

    return false;
}

spl_autoload_register('autoload_app');
spl_autoload_register('autoload_src');
spl_autoload_register('autoload_current', prepend: true);

echo sprintf('autoloader order: %s.%s', json_encode(spl_autoload_functions()), PHP_EOL);
//spl_autoload_unregister('autoload_two');
//var_dump(spl_autoload_functions());

echo (new Current())->sayHello('anik');

第 3、14 和 25 行 声明了三个方法。 这些方法中的每一个都需要引用来自正确目录的正确文件。

  • autoload_src 方法负责从 src 目录中 include 文件。
  • autoload_app 方法负责从 app 目录中 include 文件。
  • autoload_current 方法负责从 current 目录中 include 文件。

第 43、44、45 行 注册我们定义的方法。 [**spl_autoload_register**](https://www.php.net/manual/en/function.spl-autoload-register.php) 接受第一个参数,一个 回调。 第二个参数 $throw 不应该被触及 如果使用PHP ≥8.0,最后, $prepend 第三个参数,决定回调应该放在队列的顶部还是队列的底部。

第 47 行,打印出可用的注册自动加载函数。

第 51 行, echo 类方法的返回值。

现在,如果我们执行脚本,它将产生以下输出。

❯ php index.php 
autoloader order:["autoload_current","autoload_app","autoload_src"].
autoload_current: looking for "Current".
autoload_current: looking for "Source\Source".
autoload_app: looking for "Source\Source".
autoload_src: Looking for "Source\Source".
autoload_current: looking for "App\App".
autoload_app: looking for "App\App".
Current says: "Hello anik."

如果我们在输出的第一行检查自动加载器的顺序,第 43、44、45 行 现在就有意义了。

当我们实例化 Current 类时,该文件由 autoload_current 方法自动加载。Current 类扩展了 Source 类。它也应该在我们的脚本中是必需的,并且是自动完成的。只有 autoload_src 可以加载 Source 类,并且加载器方法位于自动加载器队列的第三位。这就是为什么 autoload_current,autoload_app 在加载 Source 类时在 autoload_src 之前运行。App 类也会发生同样的事情,因为 Source 类需要它。

所以,现在我相信你已经了解了 PHP 是如何自动加载文件的。

回到 Real-Time 门面代理

最后,您将非Facade类作为Facade实例处理。

也许你可以争论一下,这样做有什么意义?有什么特权吗?我不知道。我从来没有像facade那样使用任何常规类。此外,在过去的6年里,我一直在与门面被禁用的 Lumen 合作。 所以,我回答不了你的问题。 ¯_(ツ)_/¯

这就是本文的全部内容。 希望您了解它的实际工作原理。 但我更希望你自己去练习一下。 也应该可以使用 MyFacade\ 代替 Facade\ 前置命名空间。 你能想出怎么做吗?

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://medium.com/@sirajul.anik/underst...

译文地址:https://learnku.com/laravel/t/68958

本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!