Skip to content

Define the public API: mark classes final or internal #279

Open

Description

@njoubert-cleverage

Description

No class of the bundle is final or @internal (checked on main @ cd7b81f): the whole code base is an extension point, so any refactoring (constructor change, renamed protected method or property) is potentially a breaking change. For instance, the constructors of ProcessManager (#275) and of the registries can only gain optional arguments.

The Symfony BC promise relies on @internal / @final / final to define what is covered.

Proposed fix

  • v5 (preparation): add @final on the classes that are not meant to be extended, and @internal on the infrastructure classes. The Symfony DebugClassLoader then triggers a deprecation for classes extending them, giving one minor version of notice.
  • v6: turn @final into final and keep @internal.

Proposed scope, to be discussed in the PR:

Kind Classes Proposal
Infrastructure DependencyInjection\* (extension, configuration, compiler passes), EventListener\*, Logger\*Processor, Command\* @internal
Engine ProcessManager, ProcessConfigurationRegistry, TransformerRegistry, ContextualOptionResolver final (extension through decoration, events and stop checkers)
Concrete tasks and transformers Task\*, Transformer\* final by default; stay open: Abstract* classes, traits, and the ones actually extended (to be listed, e.g. in the bridge bundles)
Models / value objects Configuration\*Configuration, Model\ProcessState, events, exceptions case by case

Requirements

  • Documentation updates
    • Reference
    • Cookbooks
    • Changelog
  • Unit tests

Breaking changes

Major (v6): extending a class that becomes final, or using an @internal class, is no longer supported. The v5 @final annotations only trigger deprecations.

Activity

  1. added this to the v6.0 milestone on Oct 14, 2026
  2. added 3 commits that reference this issue on Oct 15, 2026
  3. njoubert-cleverage commented on Oct 15, 2026

    @njoubert-cleverage
    MemberAuthor

    v5 step done in #295 (merged 4d54b19, released in the next 5.x minor):

    • @final since 5.4 on 107 classes: the engine (ProcessManager, ProcessConfigurationRegistry, TransformerRegistry, ContextualOptionResolver), the models (ProcessState, ProcessHistory, SubprocessInstance, the configurations, the events, ConstraintLoader, the Filesystem files) and the concrete tasks and transformers.
    • Left open: the abstract classes, interfaces, traits, exceptions, and the classes extended by other classes of the bundle (FileReaderTask, LineReaderTask, FolderBrowserTask, CsvReaderTask, InputCsvReaderTask, Filesystem\CsvResource).
    • @internal on 13 infrastructure classes (extension, Configuration, commands, DataQueueEventListener, PhpFunctionProvider, Monolog processors, ProcessLogger, TaskLogger).
    • TaskRegistry (not released before) is already final.

    Remaining for v6.0:

    • Turn every @final since 5.4 into final (and keep @internal).
    • Narrow the return types that are too wide, now ignored with @phpstan-ignore return.unusedType because narrowing them would break child classes until they are final:
      • ProcessState::getContextualizedOptions(): ?array → array
      • PregFilterTransformer::transform(): array|string|null → string|null
    • Remove the two @phpstan-ignore comments.
    • CHANGELOG / UPGRADE note.
  4. added 4 commits that reference this issue on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions