Skip to content

fix: preserve subclass types in route group callbacks - #10644

Open
maniaba wants to merge 2 commits into
codeigniter4:developfrom
maniaba:fix/route-group-callback-static-type
Open

maniaba wants to merge 2 commits into
codeigniter4:developfrom
maniaba:fix/route-group-callback-static-type

Conversation

@maniaba

@maniaba maniaba commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Description

RouteCollection::group() passes the current collection instance to its callback with $callback($this). However, its PHPDoc declares that callback as callable(self): void. Here, self resolves to RouteCollection, even when group() is called on a subclass.

As a result, PHPStan rejects callbacks that correctly accept the application's collection subclass:

class CustomRoutes extends RouteCollection
{
}

function registerAdminRoutes(CustomRoutes $routes): void
{
    $routes->group('admin', static function (CustomRoutes $routes): void {
        $routes->get('users', 'Users::index');
    });
}

The reported error is that Closure(CustomRoutes): void does not satisfy callable(RouteCollection): void. At runtime, the callback receives the CustomRoutes instance on which group() was called, so this is valid usage.

This changes the annotation to callable(static): void. The late-static type follows the concrete collection class and therefore accurately describes the object passed to the callback. Applications can keep subclass-specific callback parameter types without overriding group(), adding application-level @method annotations, or suppressing the analysis error.

The method's implementation and native signature remain unchanged. Callbacks accepting the base RouteCollection continue to work, including when used with a subclass.

The regression test uses explicitly typed subclass callbacks for both an outer group and a nested group. It also verifies instance identity, registered routes, inherited filters, and restoration of group options afterward. These calls produce two PHPStan argument.type errors with the original self annotation and pass with static.

Validation

  • Focused PHPStan analysis of RouteCollection.php and RouteCollectionTest.php: passed.
  • vendor/bin/phpunit --no-coverage tests/system/Router/RouteCollectionTest.php: 117 tests, 167 assertions passed on PHP 8.3.35.
  • File-scoped PHP-CS-Fixer and Rector checks: passed.
  • The full CI matrix is left to GitHub Actions. No dependencies or analysis baselines were changed.

Checklist

  • Securely signed commit
  • PHPDoc corrected to describe the callback argument precisely
  • Regression test included, with the static-analysis failure reproduced before the fix
  • Conforms to the style guide
  • User guide changelog updated under Bugs Fixed for the upcoming 4.7.6 release; no upgrading instructions are needed

@carson-codeigniter4 carson-codeigniter4 Bot added the bug Verified issues on the current code behavior or pull requests that will fix them label Oct 21, 2026
Comment thread user_guide_src/source/changelogs/v4.7.6.rst
@carson-codeigniter4 carson-codeigniter4 Bot added the stale Pull requests with conflicts label Oct 26, 2026
@carson-codeigniter4

This comment has been minimized.

@maniaba
maniaba force-pushed the fix/route-group-callback-static-type branch from 06279a1 to 1e3612d Compare October 26, 2026 12:26
@carson-codeigniter4 carson-codeigniter4 Bot removed the stale Pull requests with conflicts label Oct 26, 2026

@michalsn michalsn 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.

Overall, LGTM!

Comment on lines +46 to +48
- **Routing:** Corrected the PHPDoc callback type of ``RouteCollection::group()``
to preserve the concrete collection type, allowing callbacks typed to a
``RouteCollection`` subclass to pass static analysis.

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.

Can we also make it a one-liner?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Verified issues on the current code behavior or pull requests that will fix them

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants