如何通过反射(Reflection)+注解(Attribute)来实现数组转化为对象
场景
在日常开发中,我们可能会遇到和第三方API交互的情况,一般API都返回json
格式的数据,我们会将json
转化为array
,剩下的就是操作array
来完成自己的业务逻辑。但操作array
有时候是一件令人头痛的事情,在编程的世界里,操作object
可比操作array
更让人能够理解,而且IDE
的提示也更加友好。
实际场景
我们需要解析用户的简历信息,但OCR
不是我们的主要业务,所以我们买了第三方的OCR
解析,这个简历返回的数据是比较复杂的,而且我们要对一些字段特殊处理。比如性别sex
,返回的是string
类型,但我们的数据库是int
类型,不仅仅是数据类型不一样,也可能字段名称
不一样,这个时候我们就需要做数据转化。可是这个返回数据太复杂,不仅仅是性别,还有学历中的学校信息等等。
Hydrate
为了解决上述的问题,可以通过反射Reflection
+注解Attribute
来实现一个强大的水合器Hydrate
。我们先来看代码使用,然后再分析是如何实现的。
代码
安装
composer require kabunx/hydrate -vvv
定义Entity
添加对数组entity的支持
<?php
declare(strict_types=1);
namespace App\Entities;
use Carbon\Carbon;
use Kabunx\Hydrate\ArrayEntity;
use Kabunx\Hydrate\Entity;
use Kabunx\Hydrate\Column;
/**
* 简历主体信息
*/
class Resume extends Entity
{
protected string $sourceKeyFormat = 'studly';
public int $type = 0;
public string $resumeGrade = '';
// 在这里字段发生了变化
#[Column("Married")]
public bool $isMarried = false;
// 此处省略其他字段(30多个)
// 英语等级证书,优先选择大学最高证书
#[Column("GradeOfEnglish")]
public ?EnglishGrade $englishGrade;
/**
* 计算机(IT)技能
* @var array|It[]
*/
#[Column("ITSkills")]
#[ArrayEntity(It::class)]
public array $its = []
public function setIsMarried(?string $value): bool
{
return $value ? ($value == '是' ? true : false) : false;
}
// IT技能
// 如果定义了ArrayEntity,此方法可以直接忽略
public function setIts(?array $its): array
{
if (is_null($its)) {
return [];
}
$entities = [];
foreach ($its as $it) {
$entities[] = It::instance($it);
}
return $entities;
}
}
/**
* 英语成绩
*/
class EnglishGrade extends Entity
{
protected string $sourceKeyFormat = 'studly';
public string $nameOfCertificate = '';
public string $score = '';
public ?Carbon $receivingDate;
}
/**
* IT技能情况
*/
class It extends Entity
{
protected string $sourceKeyFormat = 'studly';
// 技能类别
public string $skillType = '';
// 使用时间
#[Column(source: "TimeOfUse", target: "used_at")]
public string $usedTime = '';
// 掌握程度
public string $competencyLevel = '';
}
使用
<?php
use App\Entities\Resume;
// 此处模拟API的返回数据
$data = [
"Type" => 1,
"ResumeGrade" => '',
"Married" => '是',
"GradeOfEnglish" => [
"NameOfCertificate" => "",
"Score" => "优秀",
"ReceivingDate" => "2021-01-01"
],
"ITSkills" => [
[
"skillType" => "",
"TimeOfUse" => "",
"CompetencyLevel" => ""
]
]
];
// 如何转化为entity
$entity = Resume::instance($data);
// 这里可以操作entity了
// 如何转化为我们要的数据呐
$enttiy->toArray();
// 将会根据你的注解来转化,默认是snake格式
entity对象
转为数组
是不是很方便,在的实际工作中,我经常用。原来使用的注释doctrine/annotations
被我替换为了原生的注解
。
在entity
中我们可以使用setProperty
来修改数据,这个和laravel
中的model
修改器是一样的思路。
源码解析
具体的代码已经被我放到了GitHub
上,地址hydrate
大家可以先看,我后续会补充说明。
已经添加了单元测试,对一些函数做了重命名,在实际工作中暂时没有发现什么问题。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: