Prevent serialization of non-backed enums by innerfly · Pull Request #6796 · Codeception/Codeception · GitHub
Skip to content

Prevent serialization of non-backed enums - #6796

Merged
TavoNiievez merged 8 commits into
Codeception:mainfrom
innerfly:6753-fix-example-serialization-issue
Mar 11, 2026
Merged

TavoNiievez merged 8 commits into
Codeception:mainfrom
innerfly:6753-fix-example-serialization-issue

Conversation

@innerfly

Copy link
Copy Markdown
Contributor

Fixes an #6753, when json_encode fails to serialize non-backed enum.
Follow up #6762 (comment)

@innerfly innerfly changed the title Prevent serialization of non-backed enums #6753 Prevent serialization of non-backed enums Sep 18, 2024

@Arhell Arhell left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Naktibalda look when you have time, thanks

@W0rma

W0rma commented Dec 11, 2025

Copy link
Copy Markdown
Contributor

@innerfly

Copy link
Copy Markdown
Contributor Author

@W0rma Simple test case:

<?php

namespace Unit;

use Codeception\Attribute\DataProvider;
use Codeception\Example;
use PHPUnit\Framework\Assert as Assert;

enum ExampleEnum
{
    case FOO;
    case BAR;
}

class ExampleCest
{
    protected function EnumProvider(): array
    {
        return [
            ['expected' => ExampleEnum::FOO, 'result' => ExampleEnum::BAR],
            ['expected' => ExampleEnum::BAR, 'result' => ExampleEnum::BAR],
        ];
    }

    #[DataProvider('EnumProvider')]
    public function testEnum(Example $example)
    {
        Assert::assertSame($example['expected'], $example['result']);
    }
}

Result:

There was 1 error:
1) ExampleCest: Test enum | "Unit\\ExampleEnum","Unit\\ExampleEnum"
 Test  tests/unit/ExampleCest.php:testEnum
                                                                  
  [JsonException] Non-backed enums have no default serialization  

@burned42

Copy link
Copy Markdown
Contributor

@innerfly I think what he meant was a test that can be added to the repo showing that this is fixed with your changes and ensures it won't break again by some future changes.

Comment thread src/Codeception/Test/Descriptor.php Outdated
$signature .= ':' . substr(sha1($encoded), 0, 7);
try {
if (method_exists($testCase, 'getMetadata') && $example = $testCase->getMetadata()->getCurrent('example')) {
$encoded = json_encode($example, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will avoid breaking the whole execution, however this might result in non-unique signatures being returned as the error will just get ignored. I don't know if this is an issue or not.

But I think we could improve this even further by avoiding an exception entirely. We could convert enums manually before passing the example to json_encode. Maybe something like this:

Suggested change
$encoded = json_encode($example, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE);
$example = self::normalizeForJsonEncoding($example);
$encoded = json_encode($example, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_SUBSTITUTE);
// ...
}
private static function normalizeForJsonEncoding(mixed $value): mixed
{
return match (true) {
is_array($value) => array_map(self::normalizeForJsonEncoding(...), $value),
$value instanceof UnitEnum => $value->name,
default => $value,
};
}

@innerfly innerfly Jan 22, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@burned42 I have added manual enum convertions following your idea, and test cases to cover this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one minor nitpick, it's not necessary to manually convert backed enums as those can indeed be serialized to json and only the non-backed enums cause issues.

Unfortunately github tells me I don't have the permission to mark my discussions as resolved, but the change itself looks good to me now other than this small note 👍

The test setup looks a bit complicated, but I don't know if that can be simplified. The tests do seem to cover the changed code though :)

@innerfly innerfly Jan 23, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea of adding backed enums before unit enums was to process them before unit enums because techically every enum is UnitEnum (BackedEnum extends UnitEnum). Following
$value instanceof UnitEnum => $value->name,
would convert every enum. Ended up by adding advanced checking, this way it looks more obvious
$value instanceof UnitEnum && !($value instanceof BackedEnum) => $value->name,

@innerfly
innerfly force-pushed the 6753-fix-example-serialization-issue branch from 0fa872b to a1684b0 Compare January 21, 2026 09:44
@innerfly
innerfly force-pushed the 6753-fix-example-serialization-issue branch from a1684b0 to da50e50 Compare January 21, 2026 10:36
Comment thread src/Codeception/Test/Descriptor.php Outdated
};
}

private static function normalizeForJsonEncoding(mixed $value): mixed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is a bit off here:

Suggested change
private static function normalizeForJsonEncoding(mixed $value): mixed
private static function normalizeForJsonEncoding(mixed $value): mixed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@W0rma

W0rma commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

@TavoNiievez
TavoNiievez merged commit 14c7ebe into Codeception:main Mar 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants