When only one Dockerized project runs on a machine, a PHP upgrade looks local: change the version, rebuild the container, and verify the application.
The problem becomes more interesting when another project nearby still depends on a different PHP version.
The main question is no longer "how do I upgrade PHP?" but "where does the boundary of this upgrade actually end?"
If that boundary is unclear, one change in shared Docker infrastructure can silently alter the environment of another project.
Host PHP Should Not Define Project PHP
One of Docker’s main advantages is that each application can own its runtime.
Project A can run PHP 8.5 while project B remains on PHP 8.3, even when both run on the same machine.
Commands, tests, Composer, and background processes for each project should therefore run inside that project’s containers rather than accidentally using host PHP.
# Hostphp -v # Project Adocker exec project-a-workspace php -v # Project Bdocker exec project-b-workspace php -vA Workspace Container Should Belong to One Project
The riskiest setup is when several projects implicitly depend on the same workspace container.
An upgrade of PHP, Composer, or system packages for one project then changes the tooling of another project automatically.
A safer model is one workspace per project or one explicitly versioned service per required PHP runtime.
Project A workspace-85 php-fpm-85 Project B workspace-83 php-fpm-83 Shared machine != shared PHP runtimeContainer and Service Naming Is Part of Isolation
Clear names are not just for convenience.
When several PHP-FPM, workspace, Redis, or Nginx containers exist at the same time, ambiguous naming increases the risk of running a command in the wrong place.
The name should make the project and runtime version obvious.
docker ps --format \ 'table {{.Names}}\t{{.Image}}\t{{.Status}}'Docker Compose Project Names Must Be Isolated Too
Even when Compose files are different, identical project names can create unexpected overlap in containers, networks, or volumes.
Each environment should therefore have its own Compose project name and explicit resource names where needed.
docker compose \ -p project_a \ up -d docker compose \ -p project_b \ up -dRuntime Isolation Does Not Eliminate Port Collisions
Two projects may have separate PHP containers and still conflict at the host boundary.
For example, two Nginx containers cannot both bind the same host port at the same time.
The same applies to Redis, MySQL, Reverb, or other services when their ports are published.
When changing Docker configuration, inspect not only PHP versions but also the actual host-port bindings.
docker ps --format \ 'table {{.Names}}\t{{.Ports}}'Composer Must Run Against the Same PHP Runtime as the Application
Composer evaluates platform requirements against the PHP runtime that executes Composer itself.
If composer install runs on a host with PHP 8.5 while the application actually runs in a PHP 8.3 container, dependencies may install successfully but be incompatible with the project runtime.
Composer for a project should therefore run inside that project’s workspace container.
docker exec project-a-workspace \ composer check-platform-reqs docker exec project-b-workspace \ composer check-platform-reqsThe PHP Constraint in composer.json Is Part of the Runtime Contract
{ "require": { "php": "^8.5" }}If one project has moved to PHP 8.5, that requirement should be expressed not only in Docker configuration but also in Composer metadata.
This makes incompatibility visible earlier during dependency installation or platform checks instead of after application startup.
Do Not Share vendor Between Projects With Different Runtimes
Each project should own its own vendor directory and composer.lock.
A shared dependency directory between applications with different PHP requirements breaks the isolation model.
Updating one dependency set can then change the code loaded by another project.
Rebuild Only the Services You Intend to Change
docker compose build workspace php-fpm docker compose up -d \ workspace \ php-fpmIf only the PHP version changes, there is no reason to rebuild every service automatically.
A targeted rebuild reduces the change surface and makes verification easier because the expected affected containers are explicit.
Verify Both the Upgraded Project and the Neighboring Project
If the goal of isolation is to avoid affecting the neighboring project, verification should prove that too.
After rebuilding, inspect PHP versions in both workspaces, verify their PHP-FPM services, and run a short availability check for both applications.
Otherwise, only half of the isolation promise is tested.
docker exec project-a-workspace php -vdocker exec project-b-workspace php -v docker exec project-a-workspace \ composer check-platform-reqs docker exec project-b-workspace \ composer check-platform-reqsA Shared Docker .env Can Create Hidden Coupling
Some Docker environments select the PHP version through a variable in a shared .env.
If two projects use the same Docker files and the same configuration, changing that variable for project A can silently change the next rebuild of project B.
Runtime configuration should therefore belong to a specific project or an explicit environment profile.
PHP Isolation Should Not Hide Shared Dependencies
Even with isolated PHP runtimes, projects may still accidentally share MySQL, Redis, networks, or volumes.
That is not always wrong, but shared dependencies should be explicit.
Avoid configurations where two projects use the same database names, Redis key space, or volumes unintentionally.
A Safe Single-Project Upgrade Has an Explicit Sequence
1. Record the current runtimes of both projects.2. Verify Docker Compose project names.3. Inspect container names and ports.4. Change PHP only in the target project configuration.5. Rebuild only its workspace/php-fpm services.6. Verify php -v in the target container.7. Run composer check-platform-reqs.8. Verify the application.9. Re-check the neighboring project.10. Confirm its runtime did not change.Version Upgrades and Runtime Isolation Are Different Problems
In the separate article about safely updating PHP after critical vulnerabilities I covered the mechanics of safely upgrading PHP itself.
In a Dockerized environment, there is an additional requirement: the change must remain inside the intended project boundary.
It is not enough to verify the new PHP version. You also need to prove that neighboring projects kept their own runtimes and dependency compatibility.
What to Verify After the Upgrade
[ ] Target workspace runs the new PHP version[ ] Neighbor workspace keeps its expected older PHP version[ ] PHP-FPM works for both projects[ ] Composer platform requirements pass in both projects[ ] No host port collisions exist[ ] Compose project names are distinct[ ] vendor directories are not shared[ ] Databases/Redis/volumes did not overlap accidentally[ ] Both applications respond after the changeReal Isolation Means the Neighboring Project Did Not Change
Docker makes it possible to run several PHP versions on one machine, but containers alone do not guarantee isolation.
The boundary must be explicit in runtime, workspace, Compose project name, ports, dependencies, and configuration.
After an upgrade, verify not only that the target project received the new version but also that the neighboring project kept its own.
The strongest proof of isolation is not only "the new container works," but also "the other container did not change."
An upgrade is truly isolated only when the neighboring project remains in the same environment afterward.



