I have a PHP project that handles atomic deployments by pointing the web server at a symlink named "latest". New versions get deployed into their own folder in the "versions" folder, and then the "latest" symlink gets pointed to the new version. Super simple to set up, and as long as you delete old versions as you go (keeping, say 3 versions so you can roll back as necessary) that's pretty much all there is to it. This all gets triggered by a Gitlab CI workflow, so I can hit a button to deploy after merging changes.
Another PHP-focused way to handle this would be deploying into a new folder, then updating the nginx config to point to that folder and running `service nginx restart`.
You can also use one of the many other atomic deployment options that replace more than just the running code, at which point the only difference between deploying a PHP webapp and deploying a Java/Go/Rust webapp is what gets included in your new server/container when you build it.