Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to support deserializer objects? #83

Open
ruudk opened this issue Sep 14, 2024 · 5 comments
Open

How to support deserializer objects? #83

ruudk opened this issue Sep 14, 2024 · 5 comments

Comments

@ruudk
Copy link

ruudk commented Sep 14, 2024

First of all, thanks for creating this great extension 💙

Since there is not a Discussion board to ask questions, I create this as issue.

I have the following code:

final readonly class CoffeeMachinesResult
{
    /**
     * @param list<CoffeeMachine> $machines
     */
    public function __construct(
        #[SerializedName('__count__')]
        public int $count,
        #[SerializedPath('[coffee][machines]')]
        public array $machines,
    ) {}
}
final readonly class CoffeeMachine
{
    public function __construct(
        public int $id,
        #[SerializedPath('[machine][vendor]')]
        public CoffeeMachineVendor $vendor,
    ) {}
}
final readonly class CoffeeMachineVendor
{
    public function __construct(
        public string $label,
        #[SerializedPath('[secret]')]
        private bool $confidential,
    ) {}

    public function isConfidential() : bool
    {
        return $this->confidential;
    }
}

It's used in a test like this:

        $decoded = $this->decoder->deserializeObject(CoffeeMachinesResult::class, $json);

This extension detects these 3 classes as dead.

What's the best way to support this? I don't think I can use an EntrypointProvider for this, right?

Another thing that I'm curious of: does this extension detect the @param list<CoffeeMachine> $machines PHPDoc in CoffeeMachinesResult constructor? Because class-leak did not.

@janedbal
Copy link
Member

The easiest way is to mark serialized objects by some interface/attribute/namespace and use that in custom EntrypointProvider. If all your classes already have SerializedName or SerializedPath in its props, you can use even that for detection.


Another thing that I'm curious of: does this extension detect the @param list<CoffeeMachine> $machines PHPDoc in CoffeeMachinesResult constructor? Because TomasVotruba/class-leak#35 did not.

I'm not sure what you mean, we see the types just like PHPStan do. So if you do this:

$decoded = $this->decoder->deserializeObject(CoffeeMachinesResult::class, $json);
$decoded->machines[0]->someMethod();

then someMethod is obviously detected as used.

@ruudk
Copy link
Author

ruudk commented Sep 14, 2024

The easiest way is to mark serialized objects by some interface/attribute/namespace and use that in custom EntrypointProvider. If all your classes already have SerializedName or SerializedPath in its props, you can use even that for detection.

To be honest: that doesn't sound easy. It will pollute the code with markers to indicate this is not dead.

It can be known from the place it's called (deserialize) that the class (and its related classes) are in use.

@ruudk
Copy link
Author

ruudk commented Sep 14, 2024

Same as with #91, the dispatch call will mark something as not dead. In this issue, the deserialize call should mark it as non dead.

@janedbal
Copy link
Member

I believe we need something like this to properly support those kind of magic calls.

@janedbal
Copy link
Member

Since 0.7.0, this can be easily implemented (as shown in simple readme example).

But, I'm not sure if we can do that in a generic way (within this repository), because deserialization may and may not use constructor based on its configuration.

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

No branches or pull requests

2 participants