A secret in an environment variable is visible in docker inspect, in the process environment, and in any crash dump or error page that prints the environment.
services:
php:
secrets: [db_password]
environment:
DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
db_password:
external: true
# and the application reads the file, which means a small change:
# $password = trim(file_get_contents(getenv('DB_PASSWORD_FILE')));
The _FILE convention is what several official images already use, so the pattern is familiar even if the application has to grow a helper for it. Secrets are mounted in a tmpfs and never touch the host disk, which is the property environment variables cannot offer. On a single host without swarm the same discipline is worth keeping with a bind-mounted file and restrictive permissions, because the migration later is then nothing.