A stage that runs the analyser and the tests, produces no artefact, and is depended on by the final stage so it cannot be skipped.
FROM vendor AS check
RUN vendor/bin/phpstan analyse --no-progress
RUN vendor/bin/phpunit --no-coverage
FROM base AS final
COPY --from=check /app/composer.lock /tmp/.check
COPY --from=vendor /app/vendor /app/vendor
COPY . /app
# the COPY from `check` is doing nothing except forcing
# the stage to run. it is a dependency edge, written as a copy.
BuildKit skips any stage nothing depends on, which is a good default and means a check stage is silently unreachable unless something pulls from it. The copy of a file nobody uses is the idiom for creating that edge and it reads as a mistake, so it needs the comment. Whether tests belong in a build at all is a fair question — here it stopped an image being pushed from a branch that had not run CI.