PackageTrack
Sign in Get early access

veewee/reflecta

Unleash the Power of Optics in your code!

1.0.1 511K downloads/mo #3944 most downloaded on Packagist veewee/reflecta

What this package is like to depend on

Last release 2 months ago

29 May 2026

Release timing varies

gaps range from 2 weeks to 8 months

Some releases are documented

notes for 10 of 22 stable releases

Nothing withdrawn

no release was ever pulled

3 years old

22 releases · first in 2023

8 releases in the last 12 months

see the full history below

Release timeline

22 releases · Nov 2023 to May 2026
2024 2025 2026
Release Pre-release

Releases

latest 22
  1. 1.0.1 29 May 2026
    Release notes

    What's Changed

    New Contributors

    Full Changelog: 1.0.0...1.0.1

    Open source →
  2. 1.0.0 27 May 2026
    Release notes

    What's Changed

    • Migrate Iso/Lens from SA to STAB form (Iso<S,T,A,B>) by @veewee in #31

    Full Changelog: 0.19.0...1.0.0

    Upgrading to 1.0.0

    This release migrates Iso and Lens from the two-parameter form to the
    four-parameter STAB form. The change is almost entirely at the type
    level. Runtime method signatures are unchanged, so most code keeps working
    without edits. You only need to act if you write explicit Psalm/PHPDoc type
    annotations for optics, implement the interfaces yourself, or rely on
    compose() rejecting empty input.

    New to STAB? Read the 🧬 STAB optics walkthrough for the
    why behind the four parameters.


    TL;DR

    Before After
    Iso<S, A> Iso<S, T, A, B>
    Lens<S, A> Lens<S, T, A, B>
    IsoInterface<S, A> IsoInterface<S, T, A, B>
    LensInterface<S, A> LensInterface<S, T, A, B>

    S and A keep their old meaning (the whole, and the focus). T and B are
    the outgoing counterparts that let a write change the type. If your optic
    never changes type on write, repeat the parameters: Lens<S, S, A, A>.


    What changed

    1. Four type parameters instead of two

    Iso and Lens (and their interfaces) now carry S, T, A, B:

    /** @var Lens<Person, Person, string, string> */   // non-type-changing
    /** @var Lens<Person, AnonymizedPerson, string, HashedName> */ // type-changing

    The concrete Iso/Lens classes are invariant on all four slots; the
    IsoInterface/LensInterface are covariant on all four. See the next
    section for what that distinction means in practice.

    2. Invariant classes vs. covariant interfaces

    The variance differs between the concrete types and the interfaces, and that is
    deliberate:

    • The concrete Iso and Lens use @template (invariant). The four slots
      must match exactly. This keeps the constructor callables sound: set both
      consumes B and produces T, so the concrete type can't safely vary on
      those slots.
    • IsoInterface and LensInterface use @template-covariant. A
      LensInterface<Cat, Cat, string, string> is accepted where a
      LensInterface<Animal, Animal, string, string> is expected, so you can store
      and pass optics around by their interface.

    So when you want that subtype flexibility, type your stored properties,
    parameters, and return types against the interface (LensInterface<...> or
    IsoInterface<...>) rather than the concrete class. A property typed as
    Lens<Animal, ...> rejects a Lens<Cat, ...>; the same property typed as
    LensInterface<Animal, ...> accepts it.

    // invariant: only an exact Lens<Animal,...> fits
    /** @var Lens<Animal, Animal, string, string> */
    
    // covariant: a LensInterface<Cat,...> is also accepted
    /** @var LensInterface<Animal, Animal, string, string> */

    3. Type-changing write API

    The signatures now allow a write to produce a different type:

    • Lens::set(S, B): T
    • Lens::update(S, callable(A): B): T
    • Iso::from(B): T

    At runtime these take exactly the same arguments as before; only the declared
    types widened. Existing non-type-changing usage (B = A, T = S) is
    unaffected.

    4. compose() accepts empty input

    Iso\compose() and Lens\compose() now take array<...> instead of
    non-empty-array<...>. Composition is a monoid:

    • empty input → identity optic
    • single input → that optic, unchanged

    If you previously relied on Psalm flagging an empty compose() call, that
    check is gone.

    5. optional() return type widened

    // before
    LensInterface<S, A|null>
    // after
    LensInterface<S|null, T|null, A|null, B|null>

    6. AdjacentTemplateValidator removed

    The custom Psalm plugin that detected compose() boundary mismatches is gone.
    Boundary mismatches are now caught by standard Psalm inference from the STAB
    signatures. No configuration change is needed; just expect the diagnostics to
    come from Psalm core rather than the plugin.


    What you need to do

    Runtime-only users

    Nothing. set, update, from, compose and friends behave identically at
    runtime.

    If you annotate optics in PHPDoc

    Update two-parameter annotations to four. For the common non-type-changing
    case, duplicate:

    -/** @var Lens<Person, string> */
    +/** @var Lens<Person, Person, string, string> */
    
    -/** @param IsoInterface<Foo, Bar> $iso */
    +/** @param IsoInterface<Foo, Foo, Bar, Bar> $iso */

    If your optic genuinely changes type on write, fill in the real T/B:

    /** @var Lens<Person, AnonymizedPerson, string, HashedName> */

    If you implement IsoInterface / LensInterface yourself

    Add the T and B template parameters and update the method signatures
    (set, trySet, update, tryUpdate, from, tryFrom, optional,
    compose, inverse, asLens) to match the new interface. See
    src/Lens/LensInterface.php and src/Iso/IsoInterface.php for the reference
    shapes.

    If you depend on compose() rejecting empty arrays

    Add your own non-empty check before calling compose() if you still need it.


    Verifying your upgrade

    Run your static analyzer after bumping the dependency:

    composer update veewee/reflecta
    vendor/bin/psalm

    Most fallout shows up as InvalidArgument or MismatchingDocblockParamType on
    optic annotations. Apply the two-to-four parameter expansion above to fix them.

    Open source →
  3. 0.19.0 26 May 2026
    Release notes

    What's Changed

    • Fix compose() boundary detection under covariant Iso/Lens templates by @veewee in #30

    Full Changelog: 0.18.0...0.19.0

    Open source →
  4. 0.18.0 27 Mar 2026
    Release notes

    What's Changed

    • Split into PSL components and Bump PHP to 84 by @veewee in #27

    Full Changelog: 0.17.0...0.18.0

    Open source →
  5. 0.17.0 26 Mar 2026
    Release notes

    What's Changed

    • Optimize properties_set to clone once instead of per property by @veewee in #26

    Full Changelog: 0.16.0...0.17.0

    Open source →
  6. 0.16.0 19 Mar 2026
    Release notes

    What's Changed

    • Replace azjezz/psl with php-standard-library/php-standard-library by @veewee in #25

    Full Changelog: 0.15.0...0.16.0

    Open source →
  7. 0.15.0 11 Mar 2026
    Release notes

    What's Changed

    Full Changelog: 0.14.0...0.15.0

    Open source →
  8. 0.14.0 14 Oct 2025
    Release notes

    What's Changed

    • Upgrade PHP project to support PHP 8.5 by @veewee in #23

    Full Changelog: 0.13.0...0.14.0

    Open source →
  9. 0.13.0 06 Feb 2025
    Release notes

    What's Changed

    • Infer properties_get and properties_set settings. by @veewee in #22

    Full Changelog: 0.12.0...0.13.0

    Open source →
  10. 0.12.0 24 Jan 2025
    Release notes

    What's Changed

    • Let psalm known assignments of unknown properties by @veewee in #21

    Full Changelog: 0.11.0...0.12.0

    Open source →
  11. 0.11.0 19 Dec 2024

    Nothing published for this version

  12. 0.10.0 25 Oct 2024

    Nothing published for this version

  13. 0.9.0 06 Sep 2024

    Nothing published for this version

  14. 0.8.1 18 Jun 2024

    Nothing published for this version

  15. 0.8.0 14 Jun 2024

    Nothing published for this version

  16. 0.7.0 13 Jun 2024

    Nothing published for this version

  17. 0.6.0 12 Jun 2024

    Nothing published for this version

  18. 0.5.0 06 Jun 2024

    Nothing published for this version

  19. 0.4.0 03 May 2024

    Nothing published for this version

  20. 0.3.0 30 Jan 2024

    Nothing published for this version

  21. 0.2.0 03 Dec 2023

    Nothing published for this version

  22. 0.1.0 17 Nov 2023

    Nothing published for this version

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive