Advice order depends on cache warmth: aspects register in reverse order when their classes are autoloaded through the weaving pipeline
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 45/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- php
- Lĩnh vực
- backend, documentation, testing
Hướng nghiên cứu
Start with Container registration order, then trace advisor handling through AdvisorIndex, CachedAspectLoader, AdviceMatcher, and the compiled caches under src/Core/Cache/. Add a functional test for tied advices on cold and warm caches, remove the production_native_aspects workaround in tests/Functional/CacheWarmupIntoAnotherDirectoryTest.php, and update the advice ordering docs. Done means builds are byte-identical across cache modes, tied advice runs in aspect registration order, and the requested test, analysis, and performance commands pass.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Found while fixing #807 (PR #830).
Problem
Advices of the same kind and the same order value, coming from different aspects, are woven in a different order depending on how the aspect classes were loaded:
- Cold build, and every debug build: the aspect classes are autoloaded through the stream filter, and the aspects register in reverse registration order.
- Production kernel with a warm own cache: the aspect classes are loaded natively (skip list), and the aspects register in registration order.
Impact
- Runtime behaviour: the interceptor lists of tied advices are swapped. Their runtime execution order differs between a cold build and a warm rebuild or a
--cache-dirbuild, so the same release can run its advices in a different order depending on how its cache was produced. - Generated proxies differ between builds:
- the alias of colliding imports moves to the other aspect;
- the order of proxy methods changes;
- the key order of
_include.cachechanges.
- Builds are not reproducible: two builds of the same code are not byte-identical.
Reproduction (fixture project, production config, JIT off)
rm -rf var/cache/aspect, thenGO_AOP_CONFIGURATION=production bin/console cache:warmup:aop web/index.php. This warms the own cache.… --cache-dir=/tmp/warmrm -rf var/cache/aspect, then… --cache-dir=/tmp/colddiff -r -x _transformation.cache /tmp/cold /tmp/warmshows differences in:Main.phpSimpleEnum.phpBackedEnum.phpImportCollisionClass.php_include.cache(key order; ignore thestampline added by #816)
Debug builds, cold or warm, match the cold production build. Excluding src/Aspect/ from weaving makes all builds identical.
Cause chain
- On the first cache miss,
SourceTransformingLoader::getTransformers()callsContainer::getServicesByInterface(SourceTransformer::class). - Its
is_subclass_of($id, …)probe autoloads every pending factory id, and the aspects are pending factories. - An aspect missing from the cache goes through
AopComposerLoader, then thephp://filter, thentransformCode(), and back intogetTransformers(). The calls nest once per aspect. - At the innermost level, only the last-registered aspect is already loaded.
AdvisorIndex::getAdvisors()(reached throughConstructorExecutionTransformer::$sourceMarkers) loads and registers it first, and each outer level then adds its own aspect. - The advisors therefore end up in reverse registration order.
AbstractJoinpoint::sortAdvices()keeps the advisor order for ties, so tied advices from different aspects come out swapped. - With a warm own cache, the aspects are in the skip snapshot and load natively, so nothing nests and the order is the registration order.
A re-entry guard in getUnloadedAspects() alone does not help: the nesting enters through the container's probe for SourceTransformer.
Proposed decision for the implementing agent
Make the tie order explicit and independent of load timing (option c): sort advisors by the registration index of their aspect in the container, then by declaration order within one aspect, and only then let sortAdvices() apply the advice order.
- Why: load order becomes irrelevant. This covers every way the nesting can arise, including future ones, and the order is something users can rely on and read in the docs.
- Implementation sketch:
Containeralready keeps registrations in insertion order. Expose a stable registration index for a service id, preferably as an interface property or a small method on the internal contract, per the AGENTS rules.AdvisorIndex/CachedAspectLoaderrecord that index with each advisor.AdviceMatcher(or the code that builds interceptor lists) orders by it before the advice-order sort. Closure advisors registered without an aspect sort after aspects, in their own registration order.- Check the compiled advisor caches (
src/Core/Cache/): the stored order must be the deterministic one, so bump the format version if it changes.
- Optional follow-up (option a), as a separate issue: stop
Container::getServicesByInterface()from autoloading aspect ids while resolvingSourceTransformerservices, e.g. by resolving transformers by their registered tags or ids. This removes the nested weaving on cold builds, which is a performance and complexity win, but it is not needed for correctness once (c) is in. - Rejected: a re-entry guard only (option b). It handles today's path but leaves the order implicit.
Acceptance
- A cold build, a warm rebuild and a
--cache-dirbuild from a warm production cache are byte-identical, apart from_transformation.cacheand the include-map stamp. - Tied advices from different aspects run in aspect registration order in every mode. Add a functional test with two same-kind, same-order advices from two aspects, checked on a cold and on a warm cache.
- Remove the workaround in
tests/Functional/CacheWarmupIntoAnotherDirectoryTest.php: drop theproduction_native_aspectsfixture configuration and compare against the plainproductionconfiguration. - Document the tie order in the advice ordering docs.
composer test,composer analyze, andcomposer test:performance:transformation(the wiring changes). Run withopcache.jit=disable: the PHP 8.5.12 tracing-JIT bug breaks the functional subprocess tests.
Scoring
| Score | Why | |
|---|---|---|
| Effort | Medium | A registration-index contract on the container, carried through the advisor index and matcher, a possible advisor-cache format bump, and functional cold/warm tests. |
| Impact | Medium | It only affects applications with tied advices across aspects, but there it changes runtime behaviour between deploys, silently. |
- Ngôn ngữ chính
- PHP
- Star
- 1.7k
- Fork
- 166
- Merge trung bình
- 1 ngày 1 giờ
- Pull request đã merge (30 ngày)
- 38
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của goaop/framework
-
Enhancement
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
cache:warmup:opcache runs out of memory with the default memory_limit (128M) on larger applicationsĐang mởBug
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 55/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug To Be Discussed
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 28/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug
Độ khó 4/5 1-2 ngày Mức phù hợp với người mới 56/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Enhancement Performance
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của goaop/framework
Issue tương tự
-
enhancement priority Sales
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
novalo-dev/Prestashop-MCP-Server#201 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
web-token/jwt-framework#757 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Include flows spanning the full report time windowCó thể đã có người làm @somethingwithproof đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
Cacti/plugin_flowview#306 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug origin: upstream priority: low
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
mattytap/Mattytap-Sermons#105 ·