I've been using the same setup for a local PHP and Symfony development since 2017 and now and then I still see someone is using a less efficient setup, so I decided it deserves a write-up.
Let's start with PHP itself. There are several options for running PHP locally. You can use XAMPP, WAMP, Docker or install PHP directly. Each of them has its pros and cons and my setup uses just plain PHP from windows.php.net.
All you need to do is to download the most recent PHP from windows.php.net (use the ZIP version VS16 x64 Non Thread Safe) and unpack it somewhere. In my case I use
C:/dev/php to make the path short.
Next step is adding it to the system PATH so you can run it from anywhere with just
php. (Google a guide on how to add a directory to system PATH if you are not sure how to do it.)
Now you can run
php -v from a command line and it should print the PHP version (btw. I use cmder as my command line tool and it's awesome!).
Using multiple PHP versions
Things usually get tricky, when you need to maintain more applications where each requires a different version of PHP.
What works great for me is to version the PHP installation directory using git. I create a separate branch for each version (
php82 etc.) and checkout them when I need to work on some older stuff. I recommend using orphan branches as it makes the git history cleaner.
When upgrading to a newer patch version (e.g., 8.2.3 → 8.2.4), I delete almost everything in the directory and unpack a newer version there. I keep the
php.ini and some other files (see the next parts of the post).
I push the repo to GitLab which allows me to maintain the same PHP configuration across multiple devices.
Another advantage of this approach is that you can easily test upcoming PHP versions when they are in the beta phase to help discover potential bugs in PHP or incompatibilities in your app.
To install Composer I recommend downloading
composer.phar file (lower on the page, in "Manual Download" section) and placing it in the php directory (so it is versioned in git with the rest of the PHP setup - it was quite useful during transition from Composer v1 to v2 when usually the projects running on newer PHP versions used Composer v2 and older ones on older PHPs used v1).
To be able to run Composer with
composer command from anywhere, create a
composer.cmd file in the php directory with the following content:
php c:\dev\php\composer.phar %*
php and passes all the parameters you provided.
Just don't forget to keep the
composer.cmd files when upgrading the PHP as described above.
The best way to run a Symfony application during development is to use the Symfony CLI. But instead of using Scoop as they suggest I just download the zip linked bellow the "Binaries" heading and unzip it so the
symfony.exe is in
As we already have the
C:/dev/php directory in the system PATH, we should be able to run
symfony from command line anywhere.
To start the webserver, navigate to Symfony project directory and run
symfony server:start. If you are using it for the first time, it will prompt you to install a newly generated root certificate so it can provide
https:// for locally running application.
After starting, it will display something like this, and you should be able to access the URL in the browser.
[OK] Web server listening The Web server is using PHP CGI 8.2.4 https://127.0.0.1:8000
Database, RabbitMQ, etc. in Docker
I prefer to run everything else besides the webserver in Docker (I mean MySQL, RabbitMQ, some mail catcher etc.). There are two main advantages:
- it allows you to easily switch versions either when upgrading the project or when working on multiple projects
- it is easy to run Linux-first tools even if you use Windows for development
You can do it by adding a
docker-composer.yml file to you project and running
docker-compose up from the CLI:
version: '3' services: database: image: mariadb:10.3.18 environment: - MYSQL_ROOT_PASSWORD=pass command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci ports: - "9101:3306" mailer: image: maildev/maildev ports: - "1080:1080" - "1025:1025" rabbitmq: image: rabbitmq:3.11.11-management ports: - 5672:5672 - 15672:15672
Symfony CLI supports Docker therefore if you use standard ports in
docker-compose.yaml, it will recognize the services and will automatically configure the ENV variables such as
To utilize this automatic ENV variables setup for CLI, you have run the Symfony Commands with
symfony console, instead of
symfony console doctrine:migrations:migrate
For accessing the database outside the application, I use HeidiSQL which is Windows application for managing the database (I like it more than web tools such as Adminer or PhpMyAdmin).
Being efficient with aliases
I like using Composer Scripts to run dev tools included in the project such as PHPStan or PHP_CodeSniffer, but I hate typing long commands, so I have created an alias script in
php c:\dev\php\composer.phar %*
With that I can run
cs script with
x cs instead of
composer cs. Similarly, for
composer install, I just run
For running the Symfony Commands, I use another alias:
symfony console %*
Which allows me to run Symfony commands this way:
There is a cool feature in Symfony Command component which allows you to shorten the commands as long they are still unique. It means that
c d:m:m will run
doctrine:migrations:migrate if there isn't another command with same starting letters. And because Composer uses Symfony Command under the hood, the same applies to any Composer commands.
What setup do you use for local development? Let me know in the comments! I would be delighted to learn how to optimize my setup even further.