philiagus/parser

PHP 输入断言、解析和转换类。

v1.2.0 2020-11-09 10:45 UTC

This package is auto-updated.

Last update: 2024-09-03 14:57:55 UTC


README

PHP 类用于断言、转换和解析数据。

是否经过测试?

在以下 PHP 版本上进行了测试

  • PHP8.3

100% 测试覆盖率。测试覆盖率在 PHP8.3 上生成

我为什么需要它?

确保您的输入是预期的,是安全编码的核心原则之一。

显然还有很多,但我们必须一步一步地解决它们。

解析器的基本思想是,开发者通过代码定义一个结构,然后向它投掷一组数据。解析器确保数据遵循结构中定义的规则。

它是如何工作的?

有关如何编写自己的解析器的更深入文档和教程,请参阅这里

一个简单的例子,断言提供的值在定义的范围内

<?php
use Philiagus\Parser\Base\Subject;
use Philiagus\Parser\Parser\Assert\AssertInteger;

$integer = 100;

$parsingResult = AssertInteger::range(0, 100)
    ->parse(Subject::default($integer))
    ->getValue();

// or, also possible:
AssertInteger::range(0, 100)
    ->thenAssignTo($target)
    ->parse(Subject::default($integer))
    ->getValue();

当你开始将解析器堆叠在一起时,真正的乐趣才开始。

<?php
use Philiagus\Parser\Base\Subject;
use Philiagus\Parser\Parser\Assert\AssertFloat;
use Philiagus\Parser\Parser\Assert\AssertInteger;
use Philiagus\Parser\Parser\Logic\OneOf;
use Philiagus\Parser\Parser\Parse\ParseArray;

$input = [
    1, 1.0, 2, 4, 4.20
];

$integers = [];
$floats = [];

ParseArray::new()
    ->assertSequentialKeys()
    ->giveEachValue(
        OneOf::new()
            ->parser(
                AssertInteger::minimum(0)
                    ->thenAppendTo($integers),
                AssertFloat::minimum(0.0)
                    ->thenAppendTo($floats)
            )
    )
->parse(Subject::default($input));

// $integers will contain [1, 2, 4]
// $floats will contain [1.0, 4.20]

比如说:您有一个 API,它以 JSON 格式从客户端接收请求,并且您需要找到相关信息。

<?php
use Philiagus\Parser\Base\Subject;
use Philiagus\Parser\Parser\Assert\AssertInteger;
use Philiagus\Parser\Parser\Assert\AssertStdClass;
use Philiagus\Parser\Parser\Assert\AssertStringMultibyte;
use Philiagus\Parser\Parser\Convert\ConvertToDateTime;
use Philiagus\Parser\Parser\Parse\ParseJSONString;

$sourceValue = '{"name":"Frank Herbert","birthday":"1920-10-08"}';

$parser = ParseJSONString::new()
    ->then(
        AssertStdClass::new()
            ->givePropertyValue(
                'name',
                AssertStringMultibyte::UTF8()
                    ->giveLength(
                        AssertInteger::new()
                            ->assertMinimum(1)
                            ->assertMaximum(64)
                    )
                    ->thenAssignTo($name)
            )
            ->givePropertyValue(
                'birthday',
                ConvertToDateTime::fromSourceFormat(
                    '!Y-m-d', new \DateTimeZone('UTC'),
                    'The provided birthday is not a valid date'
                )
                    ->setTimezone(new \DateTimeZone('UTC'))
                    ->thenAssignTo($birthday)
            )
    );
    
$result = $parser->parse(Subject::default($sourceValue, 'Input', false));

if ($result->hasErrors()) {
    foreach ($result->getErrors() as $error) {
        echo $error->getPathAsString(), ': ', $error->getMessage(), PHP_EOL;
    }
    exit;
}

$today = new \DateTime();
$delta = $today->diff($birthday);
if ($today < $birthday) {
    echo "$name will be born in ", $delta->y, " years", PHP_EOL;
} else {
    echo "$name was born ", $delta->y, " years ago", PHP_EOL;
}

如果您执行此代码,结果将是“弗兰克·赫伯特出生于101年前”(至少在这次输入时是这样)。

如果将输入更改为{"name":123,"birthday":"1920-10-0f"},结果将是

Input.name: Provided value is not of type string
Input.birthday: The provided birthday is not a valid date

如果某些信息缺失怎么办?

不用担心!所有解析器都实现了Philiagus\Parser\Contract\Parser,因此您可以轻松编写自己的解析器来满足特定的需求。请查看Philiagus\Parser\Base\Parser,它是一个可以轻松扩展的基类。

一些提示

  • 如果您的解析器验证类型(例如:读取 XML 的解析器,因此非字符串是不允许的),则Philiagus\Parser\Base\OverwritableTypeErrorMessage特质可能有所帮助。
  • Philiagus\Parser\Base\Parser已经实现了基本功能,如使用->then($parser)进行链式调用等,因此您不必担心这些问题。
  • 如果您需要更多控制解析器的行为或不喜欢ResultBuilder,只需实现Philiagus\Parser\Contract\Parser接口即可与其他解析器互操作。只需注意,您必须
    • 当您进入解析器时创建一个ParserBegin主题,将提供的主题包装在另一个主题中,以确保值链保持不变
    • 尊重主题的throwOnError()信息:如果发生错误并且throwOnError()处于活动状态,您必须抛出错误(通常使用$error->throw())。相应地,如果throwOnError()未处于活动状态,您必须将错误添加到结果对象中。