Innovate faster and cut risk with PHP experts from Zend Services.
Beginning to advanced PHP classes to learn and earn global certification.
Help me choose >
Submit support requests and browse self-service resources.
Matthew Weier O’Phinney
Choosing a PHP application stack can be a challenge. The stack needs to simultaneously account for the needs of the application, and stay aligned with where that application is within its lifecycle. That's not to mention the thousand decisions you need to make between ideating and integrating your stack.
In this article, we give a high-level view of the PHP stack selection process, broken down by the stages of application lifecycle. Along the way, we touch on popular PHP stacks, the role of containers and virtual machines, and the unique considerations that teams need to make for production applications.
When we talk about a stack, we're talking about the operating system, web server, PHP, and anything PHP consumes or interacts with, including databases, queues, caches, APIs, and more. Stacks differ based on whether you're in development, continuous integration (CI), or production, with each posing its own needs and challenges.
In development, the question will be how close you want the environment to the production environment. For many, the answer will be "close enough"; tools like database abstraction, tests for PHP compatibility, and web server definition may mean you don't need the environment to be exact, so long as you can run the application. However, keeping the development and production environments as close as possible is generally a good idea, and we have tools such as virtual machines and containers to assist us.
In CI, you need the environment as close to production as possible to ensure that automated testing will actually catch bugs. Additionally, you will want to be able to orchestrate and automate setup/teardown as easily as possible, so that you can run tests quickly, and consume as few resources as possible to save costs.
In production, needs may change based on how you want to deploy and manage the stack. Will you be deploying on-premise, and self-managing? If so, how will you split services for redundancy and/or scaling? Or will you be using a cloud vendor? Will you be using cloud images? Which operating systems are available? How will you split capabilities and responsibilities between machines? If you choose to go with containers, you will need to consider the fact that you may want leaner images with reduced OS capabilities for security, performance, and scaling.
Broadly speaking, you'll likely be using some form of the LAMP stack. While LAMP stands for Linux, Apache, MySQL/MariaDB, and PHP, it has a wide range of variations:
• While Linux is the kernel, there's a plethora of distributions to choose from.
• Apache is the most commonly used web server, but there are variants such as LEMP that use nginx (the "E" stands for nginx in this case).
• MySQL/MariaDB are the most commonly used databases with PHP, but you can pick and choose the one that best suits your needs. Common choices include PostgreSQL (for OSS enthusiasts), and MS SQL Server, Oracle, and DB2 (commercial databases common in larger organizations).
• The "stack" itself may be — and generally is — multiple machines, with a cluster of database nodes, a cluster of caching nodes, a cluster of queue nodes, and a cluster of web servers. In point of fact, PHP itself does not need to run on the same server as the web server! You can have multiple php-fpm servers sitting behind one or more web servers that act as reverse proxies!
Let's dive into the various needs at the different stages of the application lifecycle.
The main question for the developer is: do you want to run everything directly on your machine natively, or do you want to launch it on demand, using VMs and/or containers?
When talking about running services natively, we're talking about launching the various services (web server, PHP, database) directly on your machine. If you're only ever developing on a single application, this can be rather convenient, as you can have everything setup and working all the time.
Running native services is particularly interesting when in early development stages, when you may need to tinker heavily with database schemas, web server configuration, and PHP configuration, and want to make changes on the fly. The downside is that when you don't need those services running, they're eating up resources. Additionally, if you need to work on more than one project, you'll find yourself needing to automate configuration changes when you switch between them.
The most popular native development stacks are XAMPP, WAMP, and MAMP.
XAMPP is one of the oldest, most-used PHP development environments. XAMPP stands for "Cross-operating system Apache, MySQL/MariaDB, PHP, and Perl", and provides the following out-of-the-box:
The tool provides a control panel for managing things like virtual hosts, Apache, MariaDB, and PHP settings, and more. Users can add plugins for popular PHP applications and tools, including WordPress, Drupal, Mautic, and phpMyAdmin. Finally, it can be used on each of Linux, Windows, or Mac OSX.
WAMP stands for "Windows, Apache, MySQL, and PHP", and provides Apache2, PHP, and MySQL configured on Windows. PHPMyAdmin is provided by default, but there are no additional plugins available.
MAMP stands for "Mac OSX, Apache, Mysql, and PHP". Interestingly, it also supports Nginx, Python, Perl, and Ruby, and can run on Windows. A paid version, MAMP PRO, allows installation of plugins, such as WordPress, Joomla, or Drupal, and provides the ability to run multiple hosts across multiple versions of PHP, solving some of the issues developers run up against when developing multiple PHP applications.
If you're developing multiple applications, or if your role involves other duties, you may want to instead spin up the services needed by the application only when you're actively developing. Virtual machines (VMs) and containers give you this flexibility, and allow each project to strictly define their exact needs. In both cases, you can get closer to precisely emulating your production environment, as the VMs or containers can exactly mimic the production services, down to the operating system.
Virtual machines run in emulation environments, and allow booting arbitrary operating systems. They are often the basis for production environments, and are roughly equivalent to cloud machine images found in Infrastructure as a Service (IaaS) platforms such as AWS and Azure.
Virtual machines can thus run any services available to the operating system they run, allowing you to run web servers, database servers, and more. You can also run several VMs in parallel, and network them, allowing you recreate your production environment locally. When it comes to virtual machines, Vagrant is your friend here, as it gives you the ability to describe the full set of services you need, and launch them, either in a single VM or as a cluster of VMs, often using code in your working directory as the basis for the services.
With Docker, you can spin up a single image, or use docker-compose to spin up a cluster of networked images. Each image describes a machine running a specific operating system, and, ideally, a single service it will expose, such as a web server, php-fpm pool, database, cache, etc. These run in a sandbox on the host system, utilizing a portion of its resources, and often sharing libraries and binaries, allowing them to run more quickly and with fewer resources than virtual machines; they often take seconds or less to start, and consume minute amounts of memory, versus the several minutes and large amounts of memory required by VMs (which need to allocate all required memory, even when not in use).
While you can run any operating system via a container, generally speaking, you want to keep the container as small as possible so it can spin up quickly; this is particularly important if you think you will be doing autoscaling, as it allows you to react quickly to traffic. As such, the operating systems in containers are often very barebones, providing only the minimum tooling necessary to launch common daemons and services. In development, you will generally use docker-compose, allowing you to orchestrate a full suite of services representing your entire production stack, and spin them up and down as needed.
The primary needs for continuous integration are automation, and mirroring the production environment as closely as possible. Depending on your application and the frequency at which you want to introduce changes, you may also want to consider speed: how quickly can you spin environments up and down, so that testing can kick off as soon as possible?
As such, the main concerns of CI are very similar to those for production, which we'll jump to next.
Production PHP stacks have a number of concerns that you may not consider during development or even CI.
Unlike development, you will generally want to run a service per machine. Your database will require redundancy, meaning a minimum of a primary and a secondary node. For performance reasons, you will want to route write requests to the primary node, and route read requests to secondary nodes; read operations are cheap, and having multiple read-only nodes ensures that the most common database operations run the most quickly and consume the fewest resources.
Similarly, cache services such as Redis can be run in clusters, and will require fewer servers with different capabilities than your web servers. Your web servers should operate idempotently, but may need to allow sharing state (sessions!) between instances — a scenario often called "session clustering".
You will need to consider how to deploy your application in order to minimize downtime. Deployments can be managed via dedicated software, such as Zend Server's Deployment daemon, or by using tools such as cloud terraform or Docker Helm. (You can even orchestrate Zend Server and ZendPHP using these tools!)
Security is always a concern in production-facing services. You need a stable operating system that is consistenly updated to provide patches against known vulnerabilities. Similarly, you will need to have processes in place to ensure you are running a PHP version with patches against known critical vulnerabilities — whether that's a currently supported community PHP version, or an LTS version such as those provided via Zend Server and ZendPHP, which backported patches for older PHP versions (as well as current PHP versions). Further, you will need processes in place for either auto-updating your PHP binaries, or quickly deploying updated versions after a testing cycle.
For performance reasons, you may need to defer execution of some tasks. If you can return a response to your user before something is done executing, use a queue. These can be dedicated queues such as ActiveMQ (which are supported by Zend sister-company OpenLogic), or Zend Server's JobQueue.
When something goes wrong in production, you will want to know when, and what happened. Application performance monitoring can be critical to keeping your application up and running. These can be provided by SaaS solutions, or by dedicated, on-premise APM tooling such as the APM included in Zend Server. Zend Server also includes code tracing tools and in-production debugging/introspection tooling via Z-Ray, which can help your production team reproduce and solve problems quickly.
Choosing a PHP stack requires careful consideration of when in the lifecycle it will be used. A common concern is ensuring that the stack used in development and continuous integration closely mirrors that used in production, to ensure new features and bugfixes will work correctly. When it comes to production, we also note its best not to go too lean; the stack should help enable things like production monitoring and debugging to ensure production issues can be resolved, and the ability to optimize for performance. While we covered a lot of material in this post, we hope that the information presented will help make your selection and curation process easier.
Zend Server makes it easy to improve web application deployment. Try it today to see how it can help improve performance, boost security, and streamline your deployment processes.
Try Zend Server Free
Running a PHP version in EOL? Keep your application secure and compliant with fully-supported and secure PHP runtimes via ZendPHP.
Development Lead for the Laminas Project, Zend by Perforce
Matthew began developing on Zend Framework (ZF) before its first public release, and led the project for Zend from 2009 through 2019. He is a founding member of the PHP Framework Interop Group (PHP-FIG), which creates and promotes standards for the PHP ecosystem — and is serving his second elected term on the PHP-FIG Core Committee.