twithers/laravel-php-attributes

在您的 Laravel 应用程序中轻松使用 PHP 8 属性

1.0.4 2023-02-23 22:18 UTC

This package is auto-updated.

Last update: 2024-09-06 02:58:20 UTC


README

Latest Version on Packagist Tests

此包可以帮助您在 Laravel 应用程序中创建和使用自己的 PHP 8 属性,而无需担心编写自己的加载器、反射方法和数据缓存。

默认情况下,您的 app 目录中的所有属性都会自动加载和缓存,并提供访问器以在需要时查找属性。可以配置此包以限制目录以及属性,以提高加载速度并最小化缓存。

安装

使用以下命令使用 composer 安装此包

composer require twithers/laravel-php-attributes

您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="TWithers\LaravelAttributes\AttributesServiceProvider" --tag="config"

这是已发布的配置文件的内容

return [
    
    /**
     * Caching will make use of Laravel's built-in file caching. Using caching will be a massive performance benefit
     * as no directories and files need to be scanned for attributes and attribute usages
     */
    'use_cache' => true,

    /**
     * By default this will scan your listed directories below for all attributes and then search for them.
     *
     * If you want to avoid the initial search, you can list your attribute classes below:
     *     'App\Attributes\Foo',
     *     App\Attributes\Bar::class,
     *
     */
    'attributes' => [

    ],

    /**
     * By default this will scan all files inside your app folder for attributes.
     *
     * If you want to limit the folders, you can adjust the namespace and the files:
     * 'App\Http\Controllers' => app_path('Http/Controllers')
     */
    'directories' => [
        'App' => app_path(),
    ],

];

您可以禁用缓存,但不太推荐,因为每个请求都会扫描和建立属性集合。

您可以通过声明来限制属性列表。空数组表示将扫描列表中目录中找到的所有属性。

您可以缩小目录搜索范围,或列出多个单独的目录以查找属性及其使用情况。确保您的数组以 $namespace => $directoryPath 的结构来确保正确找到和访问文件。

PHP 8 中的属性

首先定义属性并命名空间。然后将 Attribute 属性应用于它。定义属性后,我们可以将其添加到任何我们想要的地方:类、方法、函数、属性等。以下是如何定义和使用属性的一个示例。

#[Attribute]
class SampleAttribute
{
    public string $name;
    public string $label;
    
    public function __construct(
        string $name,
        string $label
    ){
        $this->name = name;
        $this->label = label;
    }
}

#[SampleAttribute(name: 'SampleClass', label: 'My Sample Class Label')]
class SampleClass
{
    #[SampleMethod(name: 'sampleMethod', label: 'My Sample Method Label')]
    public function sampleMethod(): bool
    { 
        return true;
    }
}

我们有一个已定义的属性 SampleAttribute,它需要一个 name 和一个 label。我们有一个使用该属性的 SampleClass,以及使用该属性的方法 sampleMethod()

在 PHP 8+ 中查找属性

属性本身没有任何作用。PHP 目前没有提供一种超级简单的方式来捕获属性和值。您将被迫使用 PHP 反射,这可能不是您曾经使用过的。反射就是反射代码。您传递一些信息,例如类名、方法名等,Reflection API 将提供您需要了解的所有信息...包括属性。

以下是您当前如何使用反射 API 来查找属性的方法。

$reflectionClass = new ReflectionClass(SampleClass::class);
$attributes = $reflectionClass->getAttributes(SampleMethod::class);
if (count($attributes)){
    $attribute = $attributes[0]->newInstance();
    dump($attribute->name); // "SampleClass"
    dump($attribute->label); // "My Sample Class Label"
}

$reflectionClass = new ReflectionClass(SampleClass::class);
$reflectionMethod = $reflectionClass->getMethod('sampleMethod');
$attributes = $reflectionMethod->getAttributes(SampleMethod::class);
if (count($attributes)){
    $attribute = $attributes[0]->newInstance();
    dump($attribute->name); // "Sample Method"
    dump($attribute->label); // "My Sample Method"
}

这段代码不多,但很容易理解。但是,如果您在应用程序中广泛使用属性,您很快就会发现自己重复这段代码。

进入 Laravel PHP Attributes

使用

访问 AttributeCollection API

此包提供了 Attributes 门面,帮助您在处理之后访问存储的属性集合数据。您还可以在应用程序中为 AttributeCollection 类提供类型提示,Laravel 将自动加载初始化的属性集合。

Attributes 门面和 AttributeCollection 提供以下有用的方法

Attributes::findByClass(string $className): ?AttributeTarget
Attributes::findByClassMethod(string $className, string $methodName): ?AttributeTarget
Attributes::findByClassProperty(string $className, string $propertyName): ?AttributeTarget
Attributes::findTargetsWithAttribute(string $attributeName): AttributeTarget[]

AttributeTarget 是属性附加到的类、方法或属性。AttributeTarget 具有以下结构

  • int $type:指示目标是否为类、方法或属性
  • 字符串 $className:被目标或包含属性的类的完整命名空间名称
  • ?string $identifier:方法或属性的名称
  • allAttributes(): AttributeInstance[]:获取所有附加属性列表的方法(包括 $name 和实例化的 $instance

以下是上述代码的修改方式

$attributes = Attributes::findByClass(SampleClass::class)->allAttributes();
dump($attributes[0]->instance->name); // "SampleClass"
dump($attributes[0]->instance->label); // "My Sample Class Label"

$attributes = Attributes::findByClassMethod(SampleClass::class, 'sampleMethod')->allAttributes();
dump($attributes[0]->instance->name); // "Sample Method"
dump($attributes[0]->instance->label); // "My Sample Method"

AttributeTarget API

AttributeTarget 类还公开了一些有用的方法,用于查找特定属性

AttributeTarget::allAttributes(): AttributeInstance[]
AttributeTarget::hasAttribute(string $attributeName): bool
AttributeTarget::findByName(string $attributeName): AttributeInstance[]

独立使用

如果您不想使用 Laravel 服务提供器的自动加载和缓存属性,您可以从加载的服务提供程序列表中删除它。如果您知道相关信息,可以使用 AttributeAccessor 类来查找属性。以下是可以使用的方法

AttributeAccessor::forClass(string $className): ?AttributeInstance[]
AttributeAccessor::forClassMethod(string $className, string $methodName): ?AttributeInstance[]
AttributeAccessor::forClassProperty(string $className, string $propertyName): ?AttributeInstance[]

如果找不到类、方法或属性,它将返回 null,否则,每个静态函数都会查找所有附加属性,并返回一个包含具有 $name$instance 属性的 AttributeInstances 数组的数组供您使用。

清除属性缓存

默认情况下,属性将在首次请求时查找和处理,并将结果缓存起来。后续请求将使用缓存数据来避免昂贵的处理时间。这意味着对属性或使用属性的更改将需要清除缓存。默认情况下(除非您的环境设置为将文件存储在不同的位置),缓存文件存储在 bootstrap\cache\attributes.php 中,可以手动删除。您还可以使用以下命令

php artisan attributes:clear

在部署过程中使用此命令将确保添加的属性被正确缓存。

测试

./vendor/bin/phpunit

贡献

欢迎所有贡献。

谢谢!

contrib.rocks 制作。

许可证

MIT 许可证(MIT)。有关更多信息,请参阅 许可证文件