Skip to content

Removed TypedOptional helper - #51

Merged
petrknap merged 1 commit into
mainfrom
removed-typed-optionals
Oct 13, 2026
Merged

petrknap merged 1 commit into
mainfrom
removed-typed-optionals

Conversation

@petrknap

@petrknap petrknap commented Oct 11, 2026 •

Copy link
Copy Markdown
Owner
  • This pull request does not contain any breaking change.
  • I asked the AI to briefly summarize, use and improve the feature(s), and I'm okay with the output:

What do you think about this change?

This change represents a major architectural simplification of the library by completely removing the built-in system of strongly-typed/registered optionals (TypedOptional, AbstractOptional, GenericOptional, and NonGenericOptional) in favor of a simpler, lighter approach using an OptionalOverrides trait.

Key Aspects of the Change

  • Removal of Type Registry and Dynamic Subclassing:
    The feature removes the TypedOptional helper class and the logic that automatically looked up and instantiated custom typed subclasses (like OptionalString or OptionalArray) when calling Optional::of().

  • Introduction of OptionalOverrides:
    Instead of complex inheritance traits for different types, users now implement custom optional classes by extending the base Optional class and using the new OptionalOverrides trait to enforce return types (self) for static factories and methods like map().

  • Cleaner Implementation & Testing:

  • Several abstract methods and support checks (isSupported()) within Optional have been removed.

  • Test suites have been cleaned up significantly, replacing complex multi-type registry tests with streamlined verification for OptionalOverrides.

Benefits

  1. Reduced Maintenance Burden: Eliminates meta-programming patterns, type registration overhead, and complex factory resolution logic.
  2. Better Flexibility: Developers can easily create their own concrete wrapper classes (e.g., MyOptional) with minimal boilerplate without needing a global registry or explicit support validation checks.
  3. Streamlined Static Analysis: Relies more transparently on standard PHP/PHPStan generics via traits rather than dynamic type routing.

Overall, it shifts the library from a heavily opinionated, magic-driven type registry system to a leaner, more standard, and predictable design.

Does it contain any issue?

Based on a review of the provided code and diff, the changes are logically sound, clean, and free of apparent bugs, syntax errors, or static analysis issues.
Here is a breakdown of why the implementation is solid:

1. Code Consistency & Correctness

  • Factory and Method Overriding: The new OptionalOverrides trait correctly delegates static factories (of, ofNullable, ofFalsable, ofSingle, empty) and instance methods (filter, map) to the parent Optional class while enforcing self return types for custom subclasses.
  • Re-mapping in map(): In OptionalOverrides, map() explicitly wraps the result via self::ofNullable(parent::map($callback)->orElse(null)). This ensures that when custom optional subclasses (like Some\Optional) call map(), they correctly return an instance of their own class rather than the base Optional class.

2. Test Coverage & Verification

  • Test Alignment: All references to the deprecated/deleted typed classes (OptionalString, OptionalArray, OptionalObject, etc.) were removed from tests and replaced with Some\Optional.
  • New Assertions: A dedicated test suite (OptionalOverridesTest) was added to automatically verify that methods overridden by the trait correctly declare a self return type and maintain matching documentation comments.

3. Architectural Note (Breaking Change)

While the code itself does not contain bugs, this is a breaking architectural change because it completely removes the global type registry (TypedOptional) and specialized traits (AbstractOptional, GenericOptional, NonGenericOptional). Any consumer code relying on automatic type lookups via TypedOptional::register() will need to be updated to use the new OptionalOverrides approach.

@petrknap petrknap self-assigned this Oct 11, 2026
@petrknap petrknap added the enhancement New feature or request label Oct 11, 2026
@petrknap
petrknap force-pushed the removed-typed-optionals branch 12 times, most recently from 47770ed to 779879b Compare October 13, 2026 17:09
@petrknap
petrknap force-pushed the removed-typed-optionals branch from 779879b to 119b7ee Compare October 13, 2026 17:16
@petrknap
petrknap marked this pull request as ready for review October 13, 2026 17:45
@petrknap
petrknap merged commit 6537e77 into main Oct 13, 2026
2 checks passed
@petrknap
petrknap deleted the removed-typed-optionals branch October 13, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant