Skip to content

[DependencyInjection] Proxy does not work well with inheritance #60765

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

Open
lyrixx opened this issue Jun 11, 2025 · 6 comments
Open

[DependencyInjection] Proxy does not work well with inheritance #60765

lyrixx opened this issue Jun 11, 2025 · 6 comments

Comments

@lyrixx
Copy link
Member

lyrixx commented Jun 11, 2025

Symfony version(s) affected

all?

Description

I have an application (castor) that recently has stopped building.

The failure is only with PHP 8.4. We use Symfony 7.2.* but it's broken also on Symfony 7.3

I get the following error, when the application starts

The real instance class RepackedApplication is not compatible with the proxy class App\Application. The proxy must be a instance of the same class as the real instance, or a sub-class with no additional properties, and no overrides of the __destructor or __clone methods

How to reproduce

I made a reproducer, available in the following repo

I also tried the following line, instead of the faulty line:

$services->get(Application::class)->class(RepackedApplication::class);
@stof
Copy link
Member

stof commented Jun 11, 2025

this looks weird, as it does not look like the service is configured as lazy here, and so I don't see why we would validate a proxy class.

@stof
Copy link
Member

stof commented Jun 11, 2025

And RepackedApplication is also not overriding anything.

/cc @nicolas-grekas

@lyrixx
Copy link
Member Author

lyrixx commented Jun 11, 2025

this looks weird, as it does not look like the service is configured as lazy here, and so I don't see why we would validate a proxy class.

The application is marked as Lazy

And RepackedApplication is also not overriding anything.

Indeed, I tried to make the reproducer as small as possible !


This code used to work. I suspect the issue comes from PHP!

@lyrixx
Copy link
Member Author

lyrixx commented Jun 11, 2025

I may have found the culprit. When I dumped the compiled compiler I get

    "App\Application" => Symfony\Component\DependencyInjection\Definition^ {#32                                                                                                             
      -class: "RepackedApplication"                                                                                                                                                         
      #arguments: array:1 [
        0 => Symfony\Component\DependencyInjection\TypedReference^ {#147
          -id: "App\Foo"
          -invalidBehavior: 1
          -name: null
          -type: "App\Foo"
          -attributes: []
        }
      ]
    }
    "App\Foo" => Symfony\Component\DependencyInjection\Definition^ {#44
      -class: "App\Foo"
      #arguments: array:1 [
        0 => Symfony\Component\DependencyInjection\Reference^ {#149
          -id: ".lazy.App\Application"
          -invalidBehavior: 1
        }
      ]
    }
    ".lazy.App\Application" => Symfony\Component\DependencyInjection\Definition^ {#148
      -class: "App\Application"
      #arguments: array:1 [
        0 => array:1 [
          0 => Symfony\Component\DependencyInjection\TypedReference^ {#150 …5}
        ]
      ]
    }
  ]
  • Service App\Application => has class RepackedApplication
  • Service App\Foo => has argument .lazy.App\Application
  • Service .lazy.App\Application => has class App\Application ❌ This is wrong here.

Note

I editer symfony to hardcode RepackedApplication in my service definition, and it worked!


So I suspect two things

  • Symfony has always been broken here
  • PHP added a check somewhere that break castor

@lyrixx
Copy link
Member Author

lyrixx commented Jun 11, 2025

I manage to make a reproducer as smaller as possible (I guess)

<?php

class Application
{
    public function __construct(
        private string $name = 'my-app',
    ) {}

    public function getName(): string
    {
        return $this->name;
    }
}

class RepackedApplication extends Application
{
}

$application = new ReflectionClass(Application::class)->newLazyProxy(fn () => new RepackedApplication());

$application->getName();

I ran it on https://3v4l.org/TfgGE, and it's always the same error. So PHP may have not changed?!
So maybe it was Symfony? This is strange, the issue has popped on castor while we didn't updated our vendor (composer.lock is commited)


Should I open an issue on PHP.net too ?

@stof
Copy link
Member

stof commented Jun 11, 2025

this is because you don't make the service lazy. You make only the autowired argument lazy, which creates a lazy proxy based on the autowired type (which is the application type).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants