支持 Laravel.io 的持续发展 →

PHP 属性在 Laravel 中

2024年2月9日 阅读时间:4分钟

问候 PHP 属性

属性能够为代码中的声明(类、方法、函数、参数、属性和类常量)添加结构化、机器可读的元数据信息。

我认为这个定义很准确,并且我确信大多数阅读这篇文章的开发者至少遇到过一次属性。如果您还没有,它们本质上是为类添加的元数据。

到目前为止,您可能想知道它们与 PHPDOCs 有何不同?嗯,它们是一等公民,它们是 真正的 PHP 类,是的,我知道,这改变了整个游戏;您不需要编写 正则表达式 来从 PHPDOCs 中提取信息,您甚至可以在属性的特性中维护某种形式的状态。

由于我在聚会上来晚了,所以有很多经典的属性示例。那么,为什么不利用它们来构建一些酷炫的东西呢?

使路由可切换

在与团队合作时,我经常收到其他开发者(尤其是前端开发者)的消息,告知我某个路由无法按预期工作。有时候,我真希望能容易地禁用特定环境(比如测试环境)中的路由,同时保持本地功能正常。这样,我和我的后端开发者团队能够在其上进行工作,推送代码,并保持我们的典型工作流程,而无需担心意外使用。偶尔,这只是一个需要留在测试环境中的新路由。

所以,思考这个问题,我觉得如果能标记某个操作为禁用或忽略,会不错。你知道吗?通过使用属性,这变得超级简单,而且也很干净。

我们先创建一个属性。我会将其命名为Ignore,它将有单个属性叫做in

<?php

namespace App\Attributes;

use Attribute;

#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Ignore
{
    public function __construct(
        public array $in = ['production']
    ) {
    }
}

这就完成了,你刚刚创建了一个属性,你还会注意到我们已经将其作用域限制在类和方法上,允许这个属性仅放在这两个实体上。

现在,我们可以这样使用它


namespace App\Http\Controllers;

use App\Attributes\Ignore;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Symfony\Component\HttpFoundation\Response

class TwoFactorQrCodeController extends Controller
{
    #[Ignore(in: ['production', 'staging'])]
    public function show(Request $request): Response
    {
        if (is_null($request->user()->two_factor_secret)) {
            return [];
        }

        return response()->json([
            'svg' => $request->user()->twoFactorQrCodeSvg(),
            'url' => $request->user()->twoFactorQrCodeUrl(),
        ]);
    }
}

你可以看到这已经很容易理解了,在生产环境和测试环境中忽略。然而,我们还需要使这具有功能性,有几个方法可以实现这一点,最简单的是使用中间件。

让我们创建一个中间件,我将命名为IsRouteIgnored,你可以自由选择你喜欢的任何名字

php artisan make:middleware IsRouteIgnored

现在我们可以实现逻辑,思路很简单:我们拦截使用这个中间件的路由请求,然后检查这个操作是否有Ignore属性,如果有,我们检查当前环境是否允许有这个路由。

为此,我们将使用反射API的魔法,让我们深入研究代码

<?php

namespace App\Http\Middleware;

use Closure;
use ReflectionMethod;
use App\Attributes\Ignore;
use Illuminate\Http\Request;
use Illuminate\Routing\Route;
use Symfony\Component\HttpFoundation\Response;

class IsRouteIgnored
{
    public function handle(Request $request, Closure $next): Response
    {
        $route = $request->route();

        if (!($route instanceof Route) || $route->action['uses'] instanceof Closure) {
            return $next($request);
        }

        $reflection = new ReflectionMethod($route->getControllerClass(), $route->getActionMethod());

        $attributes = $reflection->getAttributes(Ignore::class);

        if (!empty($attributes) && in_array(config('app.env'), $attributes[0]->newInstance()->in)) {
            abort(404);
        }

        return $next($request);
    }
}

我们在路由指向的方法上创建了一个反射,因此我们检索Ignore属性。默认情况下,属性不可重复,这意味着它们只能在实体中使用一次。由于我们只对Ignore属性感兴趣,最终我们会得到一个只有一个元素的数组。

现在我们可以通过调用newInstance()来实例化这个属性,返回到常规类的领地。然后我们可以检查在in属性中应该忽略这个路由的环境。在这个例子中,该路由将在生产环境和测试环境中返回404响应,但在本地和测试环境中将正常工作。

之后,你可以在全局范围内或API路由中注册这个中间件,就像你通常做的那样,并且你可以通过标记属性来忽略路由。

结论

仅仅几行代码,我们就启用了可切换的路由。虽然实现相对简单,但这个示例旨在展示属性的力量。我的意思是,这有多酷?在你们选择的特定环境中切换路由的开关,你可以将Ignore属性调整为仅从除你指定的环境外的所有环境中排除该路由,选项是无限的。

下次你考虑标记一个类为特定某物时,考虑试一下属性!🪄

最后更新于5个月前。

driesvints, mohaaosman, muetze, ya27cine, josemalcher 喜欢这篇文章

5
喜欢这篇文章吗?让作者知道并为他们鼓掌!
oussamamater (Oussama Mater) 我是一名软件开发者和CTF玩家。我使用Laravel和Vue.js将想法变成应用程序🚀

你可能还喜欢这些文章

2024年3月11日

使用 Larastan 将你的 Laravel 应用从 0 到 9 进行优化

在代码执行前发现 Laravel 应用中的 bug 是可能的,多亏了 Larastan...

阅读文章
2024年7月19日

不使用 traits 标准化 API 响应

我注意到大多数用于 API 响应的库都使用 traits 实现,...

阅读文章
2024年7月17日

在 Laravel 项目中使用 Discord 通知收集反馈

如何在 Laravel 项目中创建反馈模块,并在收到消息时通过 Discord...

阅读文章

我们想感谢这些 令人惊叹的公司 对我们的支持

您的标志在这里?

Laravel.io

Laravel 问题解决、知识共享和社区建设的门户。

© 2024 Laravel.io - 版权所有。