You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JMSSerializer:如何为同类型属性实现差异化序列化处理?

同一类型在不同序列化场景下的差异化处理方案

问题背景

已知可以为整个类型声明自定义处理器,但实际场景中需要对同一类型采用不同的序列化逻辑。比如实体Foo有个int类型的属性$popularity,序列化时希望通过PopularityProcessor的process方法把值乘2再输出,但因为是int类型没法注册全局自定义处理器,需要针对性的解决方案。

相关代码示例

class Foo {
    public int $popularity = 10;
}

class PopularityProcessor {
    public function process(int $popularity) { 
        return $popularity * 2; 
    }
}

原映射配置:

App\Entity\Foo:
    properties:
        popularity: ~

解决方案

方案一:属性级访问器

直接在实体类里加一个专门用于序列化的getter方法,然后在映射配置里指定使用这个方法取值。

修改Foo类:

class Foo {
    public int $popularity = 10;

    // 专门给序列化用的getter
    public function getSerializedPopularity(): int {
        $processor = new PopularityProcessor();
        return $processor->process($this->popularity);
    }
}

更新YAML映射配置:

App\Entity\Foo:
    properties:
        popularity:
            accessor:
                getter: getSerializedPopularity

这样序列化时就会调用这个自定义getter,自动把值乘2输出。

方案二:序列化组+上下文处理器

如果需要多场景切换,比如有时候乘2,有时候用原值,可以用序列化组配合上下文感知的归一化器。

先写一个自定义归一化器:

use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;

class PopularityContextNormalizer implements ContextAwareNormalizerInterface, SerializerAwareInterface {
    private SerializerInterface $serializer;

    public function normalize($object, string $format = null, array $context = []) {
        // 先让默认序列化逻辑处理
        $data = $this->serializer->normalize($object, $format, $context);
        
        // 如果指定了对应分组,就处理popularity值
        if (in_array('popularity_multiply', $context['groups'] ?? [])) {
            $processor = new PopularityProcessor();
            $data['popularity'] = $processor->process($data['popularity']);
        }
        return $data;
    }

    public function supportsNormalization($data, string $format = null, array $context = []): bool {
        // 只对Foo实例且包含指定分组的请求生效
        return $data instanceof Foo && in_array('popularity_multiply', $context['groups'] ?? []);
    }

    public function setSerializer(SerializerInterface $serializer) {
        $this->serializer = $serializer;
    }
}

使用的时候指定分组即可:

// 需要乘2的场景
$serializer->serialize($foo, 'json', ['groups' => ['popularity_multiply']]);

// 不需要处理的场景,不指定这个分组就行
$serializer->serialize($foo, 'json');

方案三:属性注解指定专属处理器(Symfony环境)

如果用注解配置映射,可以直接在属性上绑定专属的处理器:

先写一个针对单个属性的归一化器:

use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

class SinglePropertyPopularityNormalizer implements NormalizerInterface {
    public function normalize($value, string $format = null, array $context = []) {
        $processor = new PopularityProcessor();
        return $processor->process($value);
    }

    public function supportsNormalization($data, string $format = null): bool {
        // 只处理int类型,结合上下文可进一步限制为Foo的popularity属性
        return is_int($data);
    }
}

然后在Foo类的属性上用注解指定:

use Symfony\Component\Serializer\Annotation\Context;

class Foo {
    #[Context(normalizer: [SinglePropertyPopularityNormalizer::class])]
    public int $popularity = 10;
}

这样序列化这个属性时就会自动调用指定的处理器。

内容的提问来源于stack exchange,提问作者ozahorulia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:33:29