Problem/Motivation

The `ProxyBuilder` class generates invalid PHP code when a method has `static` as return type (PHP 8+ feature). It incorrectly outputs `\static` instead of `static`, causing a PHP Fatal error:

PHP Fatal error: '\static' is an invalid class name in .../ProxyClass/Hook/ContentHooks.php on line 73

In `core/lib/Drupal/Component/ProxyBuilder/ProxyBuilder.php`, lines 239-242, the code checks if the return type is not built-in and prepends a backslash:

php
if (!$return_type->isBuiltin()) {
  // The parameter is a class or interface.
  $signature_line .= '\\';
}

The `static` return type is not a built-in type (`isBuiltin()` returns `false`), but it's also not a class/interface - it's a PHP keyword that should not have a backslash prefix. The code already handles `self` specially (line 244-246), but `static` was not considered.

Steps to reproduce

1. Have a service class that implements `ContainerInjectionInterface` with the `create()` method using `static` return type:

php
class ContentHooks implements ContainerInjectionInterface {
  public static function create(ContainerInterface $container): static {
    return new static();
  }
}

2. Mark this service as lazy in `*.services.yml`

3. Run the proxy class generator:
bash
php core/scripts/generate-proxy-class.php 'Drupal\eca_content\Hook\ContentHooks' "modules/contrib/eca/modules/content/src"

4. Try to clear cache with `drush cr` - PHP Fatal error occurs

**Environment:**
- Drupal 11.3.2
- PHP 8.4.16
- Debian GNU/Linux 13 (trixie)
- Apache/2.4.66

**Affected module:** ECA 3.0.10 (eca_content submodule)

Proposed resolution

Add a check for `static` return type similar to how `self` is handled:

diff
if ($reflection_method->hasReturnType()) {
$signature_line .= ': ';
$return_type = $reflection_method->getReturnType();
+ $return_type_name = $return_type->getName();
if ($return_type->allowsNull()) {
$signature_line .= '?';
}
- if (!$return_type->isBuiltin()) {
- // The parameter is a class or interface.
+ if (!$return_type->isBuiltin() && $return_type_name !== 'static') {
+ // The return type is a class or interface.
+ // Note: 'static' is not built-in but also not a class, it's a PHP keyword.
$signature_line .= '\\';
}
- $return_type_name = $return_type->getName();
if ($return_type_name === 'self') {

Remaining tasks

- Review and commit patch
- Add test case for `static` return type in `ProxyBuilderTest.php`
- Regenerate affected core proxy classes (if any)

User interface changes

None.

Introduced terminology

None.

API changes

None. This is a bug fix - the API remains the same, but now correctly handles `static` return types.

Data model changes

None.

Release notes snippet

Fixed a bug where the ProxyBuilder would generate invalid PHP code (`\static` instead of `static`) for methods with `static` return type, causing a PHP Fatal error when using lazy services with `ContainerInjectionInterface::create()` on PHP 8+.

CommentFileSizeAuthor
proxybuilder-static-return-type.patch1.11 KBpimok3000

Comments

pimok3000 created an issue. See original summary.

liam morland’s picture

Issue tags: -PHP 8 +PHP 8.0
quietone’s picture

Version: 11.3.x-dev » main
Issue summary: View changes
Issue tags: -Needs review
Related issues: +#3092424: ProxyBuilder generates incorrect @see reference

Changing tags per Issue tags field and Issue tags -- special tags

Hi, Issues for Drupal core should be targeted to the 'main' branch, our primary development branch. Changes are made on the main branch first, and are then back ported as needed according to the Core change policies. The version the problem was discovered on should be stated in the issue summary Problem/Motivation section. Thanks.