A PHP deploy ships source and hopes the target has the right runtime and extensions. dotnet publish produces a directory whose contents are the application, and it can include the runtime itself.
$ dotnet publish -c Release -o ./out
$ ls out | head -5
appsettings.json
appsettings.Production.json
Orders.dll
Orders.deps.json
web.config
# or with no runtime installed on the target at all:
$ dotnet publish -c Release -r linux-x64 --self-contained true -o ./out
$ du -sh out
74M out
The self-contained build is what makes the deployment artefact genuinely portable, at the cost of shipping the framework with every release and having to rebuild for each target architecture. The framework-dependent version is a few megabytes and needs the exact major runtime on the host. Either way the artefact is built once and copied, which is a different model from the PHP habit of running composer install on the server — and it means a build machine failure blocks a deploy that would otherwise have half-succeeded.