酵母/烤盘

从关联数组对象和配置中提取数据

v0.2.0 2022-02-07 17:46 UTC

This package is auto-updated.

Last update: 2024-09-15 08:42:11 UTC


README

QA

A simple PHP 8 native object expansion (or hydration as some call it) framework

特性

  • 仅关注数据的反序列化,因此非常适合配置
  • 生成 JSON Schema(也适用于 yaml!)
  • PHP 8 属性引导
  • 简单的模板/泛型支持
  • 简单的替代格式扩展器
  • 自定义扩展器支持可以扩展出分支的对象
  • 可读性代码生成,便于调试和加速

安装

composer require yeast/loafpan

非常快速的使用

$config      = json_decode($json, true);

$loafpan     = new Loafpan($loafpanCacheDirectory);
// Don't forget to annotate your class.
$configClass = $loafpan->expand(MyConfig::class, $config);

用法

要开始使用 Loafpan,首先需要注释您的对象,在接下来的几个示例中,我们将创建一些伪类来解释细节

可扩展的对象被称为 "单元",单元必须用 Unit 注释或已注册自定义扩展器。但是,目前我们将介绍注释单元

在第一个示例中,Sandwich 是一个基于设置器的单元,将使用默认构造函数来实例化对象,然后手动设置属性。

Loafpan 是由 Field 属性引导的,这些属性表示哪些属性可以应用于对象。

// The first argument of `Unit` is the description of the object
// This is used in the JSON Schema generation
#[Unit("This is a very nice sandwich")]
class Sandwich {
    // A custom field name can be given with the `name` parameter
    #[Field(name: "title")]
    public string $name = "";
    // since PHP has no native support for generics or typed arrays (yet)
    // one can override the type, and use list<T> to define the actual type
    #[Field("The toppings of this sandwich", type: 'list<Yeast\Demo\Topping>')]
    public array $toppings = [];
}

Topping 是基于扩展器的,并且只接受一个字符串,因为这是唯一的实例化方法。

扩展器函数是公共静态函数,具有 1 或 2 个参数(可选的第二个参数是 Loafpan 实例),第一个参数定义了可以用于从对象扩展输入的类型,例如 Topping 可以仅由字符串生成。

#[Unit("What goes on the bread stays on the bread")]
class Topping {
    private function __construct(private bool $wet = false) {}
    
    #[Expander]
    public static function fromName(string $name) {
        return new static($name === 'water' ? true : false);
    }
}

尽管 Topping 仅定义了 1 个扩展器,但您可以添加多个,请注意,当类型重叠时,结果可能是不可预测的。

使用我们刚才定义的 2 个类,Sandwich 的有效 JSON 对象将是

{
  // because the "name" property has set it's name to "title",
  // the json object must use title
  "title": "Soggy sandwich",
  "toppings": [
    "water",
    "2 pounds of lead"
  ]
}

这将大致翻译为

$sandwich = new Sandwich();
$sandwich->name = "Soggy sandwich";
$sandwich->toppings = [
   Topping::fromString("water"),
   Topping::fromString("2 pounds of lead")
];

最后,创建一个 Loafpan 实例,其中包含可以写入 PHP 文件的目录,然后使用您想要扩展的类(在我们的情况下是 Sandwich)和用户输入调用 expand

以下示例展示了这种用法

$loafpan = new Loafpan($yourLoafpanCacheDirectory);
/** @var Sandwich $sandwich */
$sandwich = $loafpan->expand(Sandwich::class, [
    "title" => "Soggy sandwich",
    "toppings" => [
        "water",
        "2 pounds of lead"
    ]
]);

echo "I have a sandwich called " . $sandwich->name . " the topping:\n";
foreach ($sandwich->toppping as $topping) {
    echo " - " . ($topping->wet ? 'wet' : 'not wet') . "\n";
}

如果这里给出的选项不足以提供足够的灵活性,您始终可以实施自己的扩展器,通过在一个类上实现 UnitExpander\Yeast\Loafpan\UnitExpander)并使用 Loafpan 实例上的 registerExpander 函数或设置 Unit 属性上的 expander 参数来将其注册到 loafpan 上。

有关自定义 UnitExpanders 的示例,请参阅 src/Expander

默认扩展器

  • list<T> - 仅接受类型为 T 的数组列表
  • map<T> - 仅接受类型为 T 的关联数组
  • DateTime/DateTimeImmutable - 仅接受 ISO-8601 格式的日期字符串
  • Ramsey\Uuid\Uuid/Ramsey\Uuid\UuidInterface - 仅接受正确格式化的 UUID 字符串

待办事项

  • 生成有关无效输入的详细错误