modern app
October 31, 2023

Building a Modern Web Application

PHP Development

When building a modern web app with PHP, there are a number of things to consider. How you build it will not only affect immediate operations, but the ability to adapt and scale your application as your business grows.  

Modern web applications are built to support rapid change and exponential growth. Your enterprise is built through web-based application programming interfaces (APIs), allowing RESTful calls between different parts of your application and its services. Beyond this, following the basics of the design we discuss will ensure an application follows industry best practices.

5 Key Attributes of a Modern Web Application

Most successful web applications implement 5 core attributes, it needs to be:

  1. Socially sharable
  2. Scalable
  3. Secure
  4. Loosely coupled
  5. Cloud ready

To help explain those attributes, we'll explore through the lens of a booking application for a theoretical livery business, “Luxury Limos USA”. This hypothetical business provides limousine services nationally in the United States.

Consider the requirements of such a service as an enterprise architect. The central focus of our booking application would be to provide an easy-to-use interface for estimating the distance between multiple geographical points on a map, in addition to the duration of the trip, for scheduling and billing purposes.

There exists a number of open source tools for accomplishing these tasks, which can be deployed as microservices for geocoding (mapping addresses to a latitude and longitude) and routing (determining the distance and duration a car would travel between two or more points). An ERP system would be able to track leads, abandoned carts, send follow-up emails, and ultimately complete the invoicing process. A service mesh like Istio could be used to secure, serve and instrument these microservices. Instrumentation could look like logging popular locations, or providing statistics on the average duration or distance of a route.  

With all of these open source microservices being written in different languages, and providing different functions, PHP can support this enterprise architecture by enabling the creation of a secure, scalable social sharing application. PHP has always excelled at rapidly generating templated content, such as traversing DOM and XML. Since our app will make use of multiple services, consider the challenge of creating a social sharing deep link into a JavaScript-based mapping application which necessitates the need for a dynamic response. Consider this deep link to the Chicago Adler Planetarium. The deep link populates it with additional information about it.

image showing rich google search result for the Adler Planetarium

If the customer wrote their frontend as an SPA (Single Page Application) in a tool like Angular, and wanted to share a visualization of the map, including the date of travel, duration, distance, and cost as a social sharing link, how could this be accomplished? Instant messengers on your phone, tools like Slack and Microsoft Teams, and Facebook or Twitter/X posts all rely on backend scrapers that read the OpenGraph metadata embedded on a website. The dynamic response in a JavaScript based application won’t be picked up by these “dumb” scrapers incapable of rendering JavaScript.

Enter PHP: a PHP application could call the relevant backend services based on URL parameters, and render an image of the result for the OpenGraph og:image tag, enabling the social sharing of itineraries with family, friends, and coworkers. Considering that the API endpoints might change over time as well, writing a PHP application enables growth and allows for the adjustments needed to meet the changing landscape. 

Let’s look at the facets of how our web application must behave to meet the standards of building a modern PHP web application.

1. Social Sharing

Driving adoption of a service is a crucial aspect of the marketing organization. This is enabled by making it easy to share information about the app through what’s known as a deep link. Consider sharing a post on LinkedIn. If you weren’t able to generate a deep link to a post, you would need to tell a colleague to “log in to LinkedIn and search for Zend’s post on Modern PHP Web applications”. Since this takes time, your colleague might skip this process entirely. An easily accessible link to the information you specifically want to share is ideal. Our example limo service will use the OpenGraph standard to enable deep links and social sharing. This will enable someone to share a link for a reservation, which will display on the user’s phone as an image of their route and some other contextual information. 

2. Scalable

Scalability entails enterprises to add and remove the ability to run additional workers as needed, automatically. This is called horizontal scaling (adding more machines or Kubernetes pods), which is distinct from vertical scaling (increases the CPU, Memory, or Disk capacity of your machines to handle more requests). One of the benefits of automatic horizontal scaling is the easy management of resources. We can spin up additional Kubernetes pods as demand requires, and scale down those pods when demand subsides. An example of this on demand scaling would be  a large marketing campaign sending out an email blast with a discount code.  

This also applies to individual microservices, as they will also need to scale as demand increases on our application, but might have asymmetric requirements as it relates to load. For example, the geocoding microservice might have substantially more traffic for autocompleting addresses and destination lookups, but the routing application might be taking too long to route, causing customers to abandon their itineraries because they’re tired of waiting. With horizontal autoscaling of microservices, additional pods can be deployed automatically to satisfy performance criteria without service disruption and with cost efficiency. Considering that the PHP social sharing application will need to call every service in order to generate its result, proper instrumentation (vis a vis a service mesh like Istio, and with statistics from a tool like ZendHQ) is essential for informing  a scaling strategy. Being able to answer “why is the PHP render so slow?” could be an upstream service taking too long, or the PHP-FPM worker being throttled for CPU or memory, and trigger scaling that isn’t effective.

3. Secure

Regularly updated, PHP provides excellent security for a web application. A bit of a misnomer has developed around the idea of PHP and security. As such a long lived and successful language, PHP has enjoyed widespread usage over the years. Many experienced developers and operators have witnessed servers that have been created and subsequently neglected. These servers which were never updated, enabled newly found security flaws to persist for years after their disclosure. The key to strong security is constantly updating for new security measures, regardless of the language used; PHP is no exception.

Modern PHP enjoys frequent and strong security updates. Many Zend customers opt for PHP Long Term Support through our ZendPHP product. This is exactly what our livery business will need: an easy way to stay up to date with security while devoting our time to designing and running a forward-thinking and technology focused as this business. Our business is likely to value the benefit of having a long runway for major upgrades, and as this application could handle the personal information of its clients like an address, travel plans, or payment information – which means being diligent about client safety and security. This is done by following security best practices involving the handling of data, and by using updated and secure software.

4. Loosely Coupled

Loose coupling is the core to the design of any well written enterprise web application. This not only enables the use of a multitude of services, but also allows you to replace them as your business grows. In our livery business, we will need mapping software to determine routes, like from the airport to the client’s destination. Beyond this, scheduling to manage drivers, a booking service to allow customers to make a reservation, payment processing for billing. Each of these separate components can be plugged into our web application, which then orchestrate interactions between them. As this business grows beyond servicing a specific set of regions, perhaps they will want to change their routing microservice to a paid Software as a Service (SaaS). Switching to one that better handles clients starting at any location as well as going to any location, and updates are managed for us. Separating everything into distinct services with loosely coupled interfaces as code contracts allows us to simply replace that one booking service with another, with minimal impacts to other places in the code.

5. Cloud Ready

A cloud-ready application is one built to decouple the data from the processing being done. The aspect of cloud readiness is built into the very core of Kubernetes microservices, allowing a customer to easily transition between cloud providers that might offer additional scalability or better pricing. The different processes of our limo booking app will communicate between each other as components, creating a single stream of data or a group of messages between each other, allowing for multi-availability zone deployments and even multi-cloud operations, ensuring maximum uptime.

The 12-Factor PHP Application: A Blueprint for a Modern Web Application

A well designed PHP based web application - like our limousine service would follow the best practices of the 12 factor App.

  1. Codebase - The project is stored in a git repository, which will allow support for CI/CD (continuous integration and deployment).
  2. Dependencies – The second step is to manage our dependencies (other libraries and such). PHP often uses composer to package and manage our dependencies as needed.
  3. Config – This is more than just environmental variables for your different deployments (staging, QA, production, etc). It involves treating your code as a configuration. When using Kubernetes, you make use of yaml files, which manage coordinating your various services.
  4. Backing Services – These are all the services your app consumes through its normal use. It might be interacting with a database, SMTP, or a queue system like Beanstalkd.  
  5. Build Release Run – A tool like Jenkins could be used here, supporting the process of CI/CD (continuous integration/continuous deployment). This is where a developer pushes a commit, and automated tests run. If they all pass, a new docker image is built and deployed in Kubernetes automatically.
  6. Process – This is where your Docker images are immutable and run the same way every time, not maintaining state across reboots.
  7. Port Binding – An example would be your webserver and a PHP-FPM docker image running separately, and communicating over TCP.
  8. Concurrency – in the past, an app may have had many individual PHP processes run as child processes of Apache or Nginx. The idea with concurrency is that every process is managed internally as different threads - which are minimally visible to the app developers. Today, Horizontal Pod Autoscaling (HPA) is used to detect the CPU usage of the PHP-FPM worker pods, and have Kubernetes scale up the number of running pods when the threshold is reached. This decouples PHP from Apache or Nginx. This also means we would need to code the PHP social sharing application to not rely on state and cookies. This removes the need for Sticky Sessions, which is a 12-factor antipattern. All requests would become stateless.
  9. Disposability – Enabling your processes to startup and shutdown quickly will enable quick and elastic scaling, and rapid deployment of code changes.  
  10. Dev and Prod Parity – In the past, there have been problems and time delays between changes in a dev environment, and pushing those changes live. This issue is solved by CI/CD deploying the same versions of the docker images across lower environments and production.
  11. Logs – Logs will provide much visibility into the processes you have running. A common way to manage your logging is to let docker and Kubernetes handle this aspect. They enable log collection tools such as Loki to collect and centralize logs.
  12. Admin Processes – Outside of normal changes to an app, there are administrative actions that must occasionally occur. Restarts, DB migrations, and the like. A good way to manage this is through building docker images that contain these administrative scripts and running them as Kubernetes Jobs. 

See How to Develop 12-Factor Web Apps

In this on-demand webinar, our experts dive in on how to develop PHP applications using the 12-Factor application methodology, and the best practices every team should consider.

 

Watch the Webinar

Popular Modern Web Application Architectures

Let’s take a closer look at how our example limousine service’s app is created to embody these attributes through making the app using microservices, cloud-native, and taking a serverless approach.

Microservices

When writing our livery app, we will want to design it to be microservice-based. We would start with a strong PHP framework like Laminas. This will give us a strong base for using the sundry PHP libraries to interact with our microservices, and assist with 12-factor approaches like setting up backing services.

Cloud-Native

Our limo company may want to host its own version of the geocoding service (perhaps Pelias) and routing service (maybe GraphHopper) to generate routes for its drivers, and to assist in planning and dispatching. However as our limousine service achieves success and needs to grow, the company might find that switching to a SaaS model at some point might be more advantageous. So we would switch from a self-hosted version of our services like Pelias to paying for a hosted model, reducing the complexity of the overall enterprise architecture at the expense of a higher operational cost. Since we already treated geocoding as a micro service, it won’t be difficult to adjust the call to a new URL! Our data model will say the same, only our API call is changing.

Serverless

Depending on how much processing the PHP social sharing app uses, it might be useful to transform it into a nano service. A nano service is a single function that performs a specific task. The ultimate in micro services. Amazon Lambda is a useful tool for hosting individual nano services. For our limo services, generating our map image for the social sharing link would be a good example of a nano service, and we could utilize our existing PHP code.

A step beyond this is the general serverless apps. This is where something like Amazon Fargate will manage your boxes for you. Spinning them up and down as needed. This way, not only is hardware management completely taken care of for you, there is no need for the business to either manage their own hardware, or pay for a specific amount of hardware that they may not be using at any one time. This is a good reason why a business might consider serverless apps in their existing Kubernetes infrastructure. They will only pay for the servers that are being used, instead of paying for all the potential servers that might be needed at peak times but are not used otherwise. If a smaller business like this limo service wants to simplify its infrastructure management over time, this would be a great option to investigate.

Final Thoughts

We’ve briefly touched upon some of the things to consider when building a modern web application with PHP. Listing all the best practices to follow with the 12-factor approach could make up entire seminars and classes. The core idea is to design your app to allow scaling and adjustment as needed.

Perhaps our example company outgrows its route planning software. With an app designed around restful API calls, it is not difficult to replace the use of an microservice-based GraphHopper deployment with a different route planner altogether; according to the Leaflet mapping documentation, there are many alternatives, paid and open source. Migrations might be avoided or minimized with the use shims between the datastores and various services. Containerizing the project will not only allow CI/CD, but also aid in resource management and enable a serverless app via a service such as Amazon Fargate.

This limousine service is but one example of what a modern web application built on PHP can be like. With the rich and complex ecosystem of tools out there, an unimaginable variety of modern web applications are possible.

Want to Get the Most Out of Your PHP-Based App?

Zend experts can help. With a full range of consultative and hands-on professional services, Zend can help you achieve your vision on time and on budget.

Explore Admin as a Service  Other Professional Services

Additional Resources