Skip to content

Optimize for PHP 8.2 readonly classes#166

Merged
koriym merged 1 commit into
1.xfrom
php82-readonly-optimization
Nov 10, 2025
Merged

Optimize for PHP 8.2 readonly classes#166
koriym merged 1 commit into
1.xfrom
php82-readonly-optimization

Conversation

@koriym
Copy link
Copy Markdown
Member

@koriym koriym commented Nov 10, 2025

Summary

  • Convert classes with all readonly properties to use PHP 8.2's readonly class feature
  • Simplify property declarations by removing individual readonly modifiers when the entire class is readonly
  • Update rector.php configuration for PHP 8.2 optimizations

Changes

This refactoring leverages PHP 8.2's readonly class feature, which allows marking an entire class as readonly instead of individual properties. This results in:

  • Cleaner, more concise code
  • Better performance (minor optimization)
  • Leveraging modern PHP features now that minimum requirement is 8.2

Example

Before:

final class CacheInterceptor implements MethodInterceptor
{
    public function __construct(
        private readonly QueryRepositoryInterface $repository,
    ) {}
}

After:

final readonly class CacheInterceptor implements MethodInterceptor
{
    public function __construct(
        private QueryRepositoryInterface $repository,
    ) {}
}

Test plan

  • All tests pass (102 tests, 198 assertions)
  • Static analysis passes (PHPStan + Psalm)
  • Applied via Rector for consistency

Summary by Sourcery

Convert classes with exclusively readonly properties to PHP 8.2 readonly classes, remove redundant property modifiers, streamline attribute constructors, and update Rector configuration for PHP 8.2 compliance.

Enhancements:

  • Mark eligible classes as readonly classes and eliminate individual readonly property modifiers
  • Simplify attribute and constructor property declarations across annotation and source code
  • Refine Rector configuration to use PHP 8.2 rule sets and adjust type coverage, dead code, and code quality levels

Build:

  • Replace custom RectorConfig closure with a fluent configuration using withPaths and PHP version sets

Tests:

  • Update test classes to match readonly constructor signatures and adjust bootstrap cleanup call

- Convert classes with all readonly properties to readonly classes
- Simplify property declarations by using class-level readonly modifier
- Update rector.php configuration for PHP 8.2 optimizations
@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Nov 10, 2025

Reviewer's Guide

This PR refactors the codebase to leverage PHP 8.2 readonly classes by converting existing classes with all readonly properties to readonly class, simplifies property declarations, updates the Rector configuration to the new fluent API for PHP 8.2 support, and applies minor code cleanups across source and test files.

Class diagram for updated readonly classes

classDiagram
    class DonutRepository {
        <<readonly>>
        +QueryRepositoryInterface queryRepository
        +HeaderSetter headerSetter
        +ResourceStorageInterface resourceStorage
        +ResourceInterface resource
        +CdnCacheControlHeaderSetterInterface cdnCacheControlHeaderSetter
        +RepositoryLoggerInterface logger
        +DonutRendererInterface renderer
    }
    class QueryRepository {
        <<readonly>>
        +RepositoryLoggerInterface logger
        +HeaderSetter headerSetter
        +ResourceStorageInterface storage
        +Expiry expiry
    }
    class DonutRequest {
        <<readonly>>
        +AbstractRequest request
        +DonutRendererInterface donutStorage
        +SurrogateKeys etags
    }
    class CommandsProvider {
        <<readonly>>
        +RefreshSameCommand refreshSameCommand
        +RefreshAnnotatedCommand refreshAnnotatedCommand
    }
    class DonutCommandInterceptor {
        <<readonly>>
        +DonutRepositoryInterface repository
        +MatchQueryInterface matchQuery
    }
    class RefreshAnnotatedCommand {
        <<readonly>>
        +QueryRepositoryInterface repository
        +ResourceInterface resource
    }
    class RefreshSameCommand {
        <<readonly>>
        +QueryRepositoryInterface repository
        +MatchQueryInterface matchQuery
    }
    class CacheDependency {
        <<readonly>>
        +UriTagInterface uriTag
    }
    class CacheInterceptor {
        <<readonly>>
        +QueryRepositoryInterface repository
    }
    class FastlyCachePurger {
        <<readonly>>
        +FastlyCachePurgerInterface fastlyCachePurger
    }
    class CliHttpCache {
        <<readonly>>
        +ResourceStorageInterface storage
    }
    class CommandInterceptor {
        <<readonly>>
        +array commands
    }
    class DevEtagSetter {
        <<readonly>>
        +CacheDependencyInterface cacheDeperency
    }
    class EtagSetter {
        <<readonly>>
        +CacheDependencyInterface cacheDeperency
    }
    class Expiry {
        <<readonly>>
        +array time
    }
    class HeaderSetter {
        <<readonly>>
        +EtagSetterInterface etagSetter
    }
    class HttpCache {
        <<readonly>>
        +ResourceStorageInterface storage
    }
    class MarshallerProvider {
        <<readonly>>
        +array options
    }
    class RefreshInterceptor {
        <<readonly>>
        +RefreshAnnotatedCommand command
    }
    class RedisDsnProvider {
        <<readonly>>
    }
    DonutRepository --|> DonutRepositoryInterface
    QueryRepository --|> QueryRepositoryInterface
    DonutRequest --|> Stringable
    CommandsProvider --|> ProviderInterface
    DonutCommandInterceptor --|> MethodInterceptor
    RefreshAnnotatedCommand --|> CommandInterface
    RefreshSameCommand --|> CommandInterface
    CacheDependency --|> CacheDependencyInterface
    CacheInterceptor --|> MethodInterceptor
    FastlyCachePurger --|> PurgerInterface
    CliHttpCache --|> HttpCacheInterface
    CommandInterceptor --|> MethodInterceptor
    DevEtagSetter --|> EtagSetterInterface
    EtagSetter --|> EtagSetterInterface
    HttpCache --|> HttpCacheInterface
    HttpCache --|> DeprecatedHttpCacheInterface
    MarshallerProvider --|> ProviderInterface
    RefreshInterceptor --|> MethodInterceptor
    RedisDsnProvider --|> ProviderInterface
Loading

Class diagram for CacheVersion attribute class update

classDiagram
    class CacheVersion {
        +string value
        CacheVersion(string value)
    }
Loading

File-Level Changes

Change Details Files
Adopt PHP 8.2 readonly class syntax and simplify property declarations
  • Mark many final classes as readonly class where all constructor properties were readonly
  • Remove individual readonly modifiers from promoted constructor parameters
  • Use constructor property promotion consistently for simple properties
src/DonutRepository.php
src/QueryRepository.php
src/DonutRequest.php
src/CommandsProvider.php
src/DonutCommandInterceptor.php
src/RefreshAnnotatedCommand.php
src/RefreshSameCommand.php
src/CacheDependency.php
src/CacheInterceptor.php
src/Cdn/FastlyCachePurger.php
src/CliHttpCache.php
src/CommandInterceptor.php
src/DevEtagSetter.php
src/EtagSetter.php
src/Expiry.php
src/HeaderSetter.php
src/HttpCache.php
src/MarshallerProvider.php
src/RefreshInterceptor.php
src-annotation-deprecated/CacheVersion.php
src-annotation/RefreshCache.php
Update Rector configuration to use the new fluent API
  • Replace closure-based setup with RectorConfig::configure() fluent calls
  • Switch from paths() to withPaths() and add directories for new PHP8 tests
  • Enable PHP sets and define coverage, dead code, and code quality levels
rector.php
Apply miscellaneous code cleanups and shorthand optimizations
  • Switch environment var fallback to null coalescing operator (?:)
  • Use argument unpacking (unlink(...)) in test bootstrap cleanup
  • Condense docblocks and remove extraneous annotations
tests-pecl-ext/StorageRedisDsnModuleTest.php
tests/bootstrap.php

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 10, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Systematic codebase refactoring introducing final readonly class declarations across 25+ files while removing individual readonly modifiers from promoted constructor parameters. Updates Rector configuration to fluent API syntax, expands scanned directories, and configures PHP-level attributes. Cleans up PHPDoc annotations and applies constructor property promotion modernizations.

Changes

Cohort / File(s) Summary
Rector configuration
rector.php
Updated from closure-based to fluent RectorConfig API with expanded directory paths (demo, src, src-annotation, src-annotation-deprecated, tests, tests-pecl-ext); replaced explicit rule registrations with PHP-level attribute sets
Annotation/documentation cleanup
src-annotation-deprecated/CacheVersion.php, src-annotation/Commands.php, src-annotation/RefreshCache.php
Converted to constructor property promotion (CacheVersion) and removed/reformatted PHPDoc blocks (Commands, RefreshCache)
Core immutability refactoring
src/CacheDependency.php, src/CacheInterceptor.php, src/Cdn/FastlyCachePurger.php, src/CliHttpCache.php, src/CommandInterceptor.php, src/CommandsProvider.php, src/DevEtagSetter.php, src/DonutCommandInterceptor.php, src/DonutRepository.php, src/DonutRequest.php, src/EtagSetter.php, src/Expiry.php, src/HeaderSetter.php, src/HttpCache.php, src/MarshallerProvider.php, src/QueryRepository.php, src/RedisDsnProvider.php, src/RefreshAnnotatedCommand.php, src/RefreshInterceptor.php, src/RefreshSameCommand.php
Added final readonly class declarations; removed readonly modifiers from promoted constructor properties, shifting immutability semantics from per-property to class-level
Test updates
tests-pecl-ext/StorageRedisDsnModuleTest.php
Simplified null-coalescing syntax using ?: operator
Test fixture/helper modifications
tests/Fake/FakeMobileEtagSetter.php, tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php, tests/ResourceRepositoryTest.php, tests/ResourceStorageTest.php, tests/bootstrap.php
Added readonly to selected promoted constructor properties; updated array callback syntax from string to variadic unpacking

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Rationale: Changes follow a highly consistent, mechanical pattern applied across files (adding class-level readonly while removing property-level readonly declarations). Most edits are modifier adjustments with no logic changes or control-flow modifications. Low cognitive load per file due to repetition and predictability.

Possibly related PRs

Suggested reviewers

  • NaokiTsuchiya
  • jingu

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Optimize for PHP 8.2 readonly classes' directly and clearly summarizes the main change: converting classes to use PHP 8.2's readonly feature.
Description check ✅ Passed The description is comprehensive and clearly related to the changeset, providing summary, changes, examples, test plan, and verification details about the PHP 8.2 readonly class optimization.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • Double-check that converting to readonly classes doesn’t inadvertently allow property mutation in methods or via reflection, since individual readonly modifiers are removed.
  • Verify that the new RectorConfig fluent setup still registers all the intended rule sets and custom rules—removing explicit sets may change your transformation coverage.
  • Review the bootstrap change from array_map('unlink', …) to array_map(unlink(...), …) to ensure the unlink callback is applied correctly and won’t cause unexpected failures.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Double-check that converting to readonly classes doesn’t inadvertently allow property mutation in methods or via reflection, since individual readonly modifiers are removed.
- Verify that the new RectorConfig fluent setup still registers all the intended rule sets and custom rules—removing explicit sets may change your transformation coverage.
- Review the bootstrap change from array_map('unlink', …) to array_map(unlink(...), …) to ensure the unlink callback is applied correctly and won’t cause unexpected failures.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link
Copy Markdown

codecov Bot commented Nov 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (5ef5a69) to head (f6cc5e9).

Additional details and impacted files
@@             Coverage Diff             @@
##                 1.x      #166   +/-   ##
===========================================
  Coverage     100.00%   100.00%           
  Complexity       243       243           
===========================================
  Files             52        52           
  Lines            734       734           
===========================================
  Hits             734       734           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@koriym
Copy link
Copy Markdown
Member Author

koriym commented Nov 10, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 10, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src-annotation-deprecated/CacheVersion.php (1)

18-20: Constructor property promotion correctly applied.

The use of constructor property promotion is correct and simplifies the code. However, consider making the property readonly for immutability and consistency with the broader PR pattern of converting classes to use readonly properties.

Since this class is deprecated, this refactor is lower priority.

Apply this diff if you wish to make the property readonly:

-    public function __construct(public string $value)
+    public function __construct(public readonly string $value)
     {
     }
tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php (1)

24-25: Remove empty PHPDoc comment.

The empty PHPDoc block provides no value. Modern PHP with type hints and attributes makes this unnecessary.

Apply this diff to remove it:

-    /**
-     */
     #[Embed(rel: "comment", src: "page://self/html/comment")]
     public function onGet()
src/EtagSetter.php (2)

21-26: LGTM! Readonly class optimization correctly applied.

The conversion to final readonly class with removal of the explicit readonly modifier from the constructor property is correct. In PHP 8.2, declaring a class as readonly makes all properties implicitly readonly, so the explicit modifier is redundant.

Optional: Fix typo in property name.

The property is named $cacheDeperency (line 24) but should be $cacheDependency. This typo is also present on line 82 where the property is used. While this doesn't affect functionality, fixing it would improve code maintainability.

Apply this diff to fix the typo:

-        private CacheDependencyInterface $cacheDeperency,
+        private CacheDependencyInterface $cacheDependency,

And update the usage on line 82:

-                $this->cacheDeperency->depends($ro, $body->resourceObject);
+                $this->cacheDependency->depends($ro, $body->resourceObject);

45-45: Optional: Fix additional typos in method and parameter names.

Two additional pre-existing typos could be corrected:

  1. Line 45: Parameter name $httpCacche should be $httpCache
  2. Line 58: Method name getEtagByEitireView should be getEtagByEntireView

Apply this diff to fix these typos:

-    public function getEtagByPartialBody(HttpCache $httpCacche, ResourceObject $ro): string
+    public function getEtagByPartialBody(HttpCache $httpCache, ResourceObject $ro): string
     {
         $etag = '';
         assert(is_array($ro->body));
-        foreach ($httpCacche->etag as $bodyEtag) {
+        foreach ($httpCache->etag as $bodyEtag) {
             if (isset($ro->body[$bodyEtag]) && is_string($ro->body[$bodyEtag])) {
                 $etag .= $ro->body[$bodyEtag];
             }
         }

         return $etag;
     }

-    public function getEtagByEitireView(ResourceObject $ro): string
+    public function getEtagByEntireView(ResourceObject $ro): string
     {
         return $ro::class . serialize($ro->view);
     }

And update the call site on line 72:

-        $etag = $httpCache instanceof HttpCache && $httpCache->etag ? $this->getEtagByPartialBody($httpCache, $ro) : $this->getEtagByEitireView($ro);
+        $etag = $httpCache instanceof HttpCache && $httpCache->etag ? $this->getEtagByPartialBody($httpCache, $ro) : $this->getEtagByEntireView($ro);

Also applies to: 58-58

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ef5a69 and 7445f17.

📒 Files selected for processing (30)
  • rector.php (1 hunks)
  • src-annotation-deprecated/CacheVersion.php (1 hunks)
  • src-annotation/Commands.php (0 hunks)
  • src-annotation/RefreshCache.php (1 hunks)
  • src/CacheDependency.php (1 hunks)
  • src/CacheInterceptor.php (1 hunks)
  • src/Cdn/FastlyCachePurger.php (1 hunks)
  • src/CliHttpCache.php (1 hunks)
  • src/CommandInterceptor.php (1 hunks)
  • src/CommandsProvider.php (1 hunks)
  • src/DevEtagSetter.php (1 hunks)
  • src/DonutCommandInterceptor.php (1 hunks)
  • src/DonutRepository.php (1 hunks)
  • src/DonutRequest.php (1 hunks)
  • src/EtagSetter.php (1 hunks)
  • src/Expiry.php (1 hunks)
  • src/HeaderSetter.php (1 hunks)
  • src/HttpCache.php (1 hunks)
  • src/MarshallerProvider.php (1 hunks)
  • src/QueryRepository.php (1 hunks)
  • src/RedisDsnProvider.php (1 hunks)
  • src/RefreshAnnotatedCommand.php (1 hunks)
  • src/RefreshInterceptor.php (1 hunks)
  • src/RefreshSameCommand.php (1 hunks)
  • tests-pecl-ext/StorageRedisDsnModuleTest.php (1 hunks)
  • tests/Fake/FakeMobileEtagSetter.php (1 hunks)
  • tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php (1 hunks)
  • tests/ResourceRepositoryTest.php (2 hunks)
  • tests/ResourceStorageTest.php (1 hunks)
  • tests/bootstrap.php (1 hunks)
💤 Files with no reviewable changes (1)
  • src-annotation/Commands.php
🧰 Additional context used
📓 Path-based instructions (6)
**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Adhere to PSR-12 coding standards using PHP_CodeSniffer for all PHP source files

Files:

  • tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php
  • tests/bootstrap.php
  • src-annotation-deprecated/CacheVersion.php
  • src/CacheDependency.php
  • tests-pecl-ext/StorageRedisDsnModuleTest.php
  • src/CacheInterceptor.php
  • src/CommandInterceptor.php
  • src/RefreshInterceptor.php
  • src/DonutRequest.php
  • src-annotation/RefreshCache.php
  • tests/ResourceRepositoryTest.php
  • src/EtagSetter.php
  • src/HeaderSetter.php
  • rector.php
  • src/RefreshSameCommand.php
  • src/Cdn/FastlyCachePurger.php
  • src/Expiry.php
  • tests/ResourceStorageTest.php
  • tests/Fake/FakeMobileEtagSetter.php
  • src/RedisDsnProvider.php
  • src/MarshallerProvider.php
  • src/CommandsProvider.php
  • src/HttpCache.php
  • src/DevEtagSetter.php
  • src/DonutRepository.php
  • src/RefreshAnnotatedCommand.php
  • src/CliHttpCache.php
  • src/DonutCommandInterceptor.php
  • src/QueryRepository.php
{src,tests}/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

{src,tests}/**/*.php: Ensure code passes PHPStan at max level as configured by phpstan.neon
Ensure code passes Psalm at error level 1 as configured by psalm.xml

Files:

  • tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php
  • tests/bootstrap.php
  • src/CacheDependency.php
  • src/CacheInterceptor.php
  • src/CommandInterceptor.php
  • src/RefreshInterceptor.php
  • src/DonutRequest.php
  • tests/ResourceRepositoryTest.php
  • src/EtagSetter.php
  • src/HeaderSetter.php
  • src/RefreshSameCommand.php
  • src/Cdn/FastlyCachePurger.php
  • src/Expiry.php
  • tests/ResourceStorageTest.php
  • tests/Fake/FakeMobileEtagSetter.php
  • src/RedisDsnProvider.php
  • src/MarshallerProvider.php
  • src/CommandsProvider.php
  • src/HttpCache.php
  • src/DevEtagSetter.php
  • src/DonutRepository.php
  • src/RefreshAnnotatedCommand.php
  • src/CliHttpCache.php
  • src/DonutCommandInterceptor.php
  • src/QueryRepository.php
tests/Fake/fake-app/**

📄 CodeRabbit inference engine (CLAUDE.md)

Exclude fake application test files from static analysis

Files:

  • tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php
tests/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Place unit tests under tests/

Files:

  • tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php
  • tests/bootstrap.php
  • tests/ResourceRepositoryTest.php
  • tests/ResourceStorageTest.php
  • tests/Fake/FakeMobileEtagSetter.php
tests-pecl-ext/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Place PECL extension-related tests under tests-pecl-ext/

Files:

  • tests-pecl-ext/StorageRedisDsnModuleTest.php
src-annotation/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Define and maintain cache-related attributes #[Cacheable], #[HttpCache], #[Refresh], #[Purge] in src-annotation/

Files:

  • src-annotation/RefreshCache.php
🧠 Learnings (6)
📚 Learning: 2025-10-21T05:23:58.622Z
Learnt from: CR
Repo: bearsunday/BEAR.QueryRepository PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-21T05:23:58.622Z
Learning: Applies to {src,tests}/**/*.php : Ensure code passes PHPStan at max level as configured by phpstan.neon

Applied to files:

  • tests/bootstrap.php
  • rector.php
📚 Learning: 2025-10-21T05:23:58.622Z
Learnt from: CR
Repo: bearsunday/BEAR.QueryRepository PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-21T05:23:58.622Z
Learning: Applies to tests-php8/**/*.php : Place PHP 8-specific tests under tests-php8/

Applied to files:

  • tests/bootstrap.php
📚 Learning: 2025-10-21T05:23:58.622Z
Learnt from: CR
Repo: bearsunday/BEAR.QueryRepository PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-21T05:23:58.622Z
Learning: Applies to tests/**/*.php : Place unit tests under tests/

Applied to files:

  • tests/bootstrap.php
📚 Learning: 2025-10-21T05:23:58.622Z
Learnt from: CR
Repo: bearsunday/BEAR.QueryRepository PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-10-21T05:23:58.622Z
Learning: Applies to src-annotation/**/*.php : Define and maintain cache-related attributes #[Cacheable], #[HttpCache], #[Refresh], #[Purge] in src-annotation/

Applied to files:

  • src-annotation-deprecated/CacheVersion.php
  • src/CacheDependency.php
  • src-annotation/RefreshCache.php
  • src/HttpCache.php
  • src/CliHttpCache.php
📚 Learning: 2024-11-01T15:45:27.018Z
Learnt from: koriym
Repo: bearsunday/BEAR.QueryRepository PR: 144
File: src/StorageRedisDsnModule.php:53-68
Timestamp: 2024-11-01T15:45:27.018Z
Learning: In `src/StorageRedisDsnModule.php`, lines 58 and 59 may both bind the Redis provider, and this can be necessary in certain cases.

Applied to files:

  • tests-pecl-ext/StorageRedisDsnModuleTest.php
  • src/RedisDsnProvider.php
📚 Learning: 2024-11-01T14:52:06.297Z
Learnt from: koriym
Repo: bearsunday/BEAR.QueryRepository PR: 144
File: src-deprecated/ResourceStorageCacheableTrait.php:24-24
Timestamp: 2024-11-01T14:52:06.297Z
Learning: When deprecating the `ResourceStorageCacheableTrait` in `src-deprecated/ResourceStorageCacheableTrait.php`, it is acceptable to only add the `deprecated` annotation without adding a runtime deprecation notice using `trigger_deprecation()`.

Applied to files:

  • src/HttpCache.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review
🔇 Additional comments (27)
tests-pecl-ext/StorageRedisDsnModuleTest.php (1)

56-59: Clean simplification of the ternary operator.

The use of the Elvis operator (?:) is a more concise and idiomatic approach than repeating getenv('REDIS_SERVER') in both the condition and the true branch. The behavior remains equivalent.

src-annotation/RefreshCache.php (1)

10-10: LGTM! Clean and concise documentation.

The single-line PHPDoc format is appropriate for a simple @see reference and improves readability without changing functionality.

tests/Fake/fake-app/src/Resource/Page/Html/BlogPostingCacheControl.php (1)

19-22: LGTM! Readonly modifier correctly applied to injected dependency.

Making the repository property readonly is appropriate for enforcing immutability of the injected dependency. Note that this class cannot be converted to a full readonly class (as done elsewhere in the PR) because the public $headers property at line 15 must remain mutable for the ResourceObject framework operations.

tests/Fake/FakeMobileEtagSetter.php (1)

17-20: Readonly promotion aligns with the immutability goal.

The promoted dependency was already treated immutably, so this readonly promotion is a clean, type-safe fit with no behavioral change.

tests/bootstrap.php (1)

5-5: Nice use of first-class callables.

Switching to unlink(...) keeps the cleanup terse while staying consistent with PHP 8.2 syntax; behavior matches the prior 'unlink' callable.

src/RedisDsnProvider.php (1)

20-41: Readonly class declaration fits the provider usage.

The provider has no mutable state beyond construction, so marking it final readonly tightens contracts without impacting the get() logic.

tests/ResourceStorageTest.php (1)

22-31: Readonly promotion keeps the test double honest.

The anonymous provider treats the adapter as immutable, so marking the promoted property readonly matches runtime behavior.

src/Expiry.php (1)

7-25: Readonly class captures the intended immutability.

Marking Expiry as final readonly reflects that its time map never mutates after construction, tightening guarantees without altering behavior.

src/CliHttpCache.php (1)

19-23: LGTM – class-level readonly fits this cache adapter. Promoting the class to final readonly keeps $storage immutable without redundant property modifiers, matching PHP 8.2 semantics for readonly classes. (php.watch)

src/CacheDependency.php (1)

13-17: LGTM – readonly class keeps dependency guarantees. Declaring the class final readonly ensures $uriTag stays write-once while simplifying the constructor promotion. (php.watch)

src/CommandInterceptor.php (1)

15-21: LGTM – interceptor immutability stays intact. Switching to a final readonly class maintains the immutability of the injected command array without needing property-level modifiers. (php.watch)

rector.php (1)

7-21: Nice config modernization. Using RectorConfig::configure() with withPaths() plus withPhpSets() relies on Rector’s composer-aware PHP set discovery and keeps the level controls explicit. (getrector.com)

src/HttpCache.php (1)

14-18: LGTM – readonly aligns with storage usage. Making the HTTP cache class final readonly preserves the intended immutability for $storage while matching the broader PHP 8.2 pattern. (php.watch)

src/CacheInterceptor.php (1)

20-24: LGTM – interceptor state stays immutable. The class-level readonly declaration keeps the repository dependency write-once while leaving runtime behaviour unchanged. (php.watch)

src/RefreshAnnotatedCommand.php (1)

19-24: Readonly class conversion matches PHP 8.2 behavior.

Switching to final readonly while removing the per-property readonly keeps the immutability guarantees intact and aligns with the language feature meant to replace redundant modifiers. (php.watch)

tests/ResourceRepositoryTest.php (1)

30-31: Immutability on test providers looks good.

Marking the promoted adapter dependencies as readonly mirrors their single-assignment usage in the tests and keeps the provider state intentional. (stitcher.io)

Also applies to: 92-93

src/Cdn/FastlyCachePurger.php (1)

11-14: Readonly upgrade keeps the purger immutable.

The move to final readonly with plain promoted properties still enforces single assignment while trimming redundant modifiers, matching PHP 8.2 guidance. (php.watch)

src/DonutRequest.php (1)

13-18: Readonly class refactor keeps constructor semantics intact.

final readonly guarantees the injected collaborators remain fixed after construction while letting the syntax stay concise. (php.watch)

src/QueryRepository.php (1)

20-26: Repository readonly conversion removes redundant modifiers.

Elevating the class to final readonly maintains the single-assignment guarantee for the promoted collaborators and aligns with PHP 8.2 best practices. (php.watch)

src/MarshallerProvider.php (1)

23-29: Readonly provider setup stays valid with promoted defaults.

The class-level readonly keeps the options array immutable after construction, and using a promoted default remains allowed under the PHP 8.2 rules. (stitcher.io)

src/RefreshSameCommand.php (1)

14-19: LGTM! Correct PHP 8.2 readonly class conversion.

The class-level readonly declaration properly replaces individual property readonly modifiers, maintaining immutability while simplifying the syntax.

src/CommandsProvider.php (1)

11-16: LGTM! Consistent readonly class conversion.

The transformation correctly applies PHP 8.2's class-level readonly semantics.

src/HeaderSetter.php (1)

14-19: LGTM! Proper readonly class conversion.

The class-level readonly declaration correctly supersedes the individual property modifier.

src/DevEtagSetter.php (1)

15-20: LGTM! Readonly class conversion applied correctly.

The transformation maintains immutability guarantees while leveraging PHP 8.2's class-level readonly feature.

src/DonutCommandInterceptor.php (1)

22-28: LGTM! Readonly class conversion applied correctly.

Both constructor-promoted properties correctly leverage the class-level readonly declaration.

src/RefreshInterceptor.php (1)

14-19: LGTM! Proper readonly class transformation.

The class-level readonly declaration correctly enforces immutability for the injected command dependency.

src/DonutRepository.php (1)

15-26: LGTM! Comprehensive readonly class conversion.

All seven constructor-promoted dependencies correctly leverage the class-level readonly declaration, maintaining immutability guarantees while simplifying the syntax.

@koriym koriym force-pushed the php82-readonly-optimization branch from f6cc5e9 to 7445f17 Compare November 10, 2025 04:57
@koriym koriym merged commit a039994 into 1.x Nov 10, 2025
60 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant