PHP Development: Modern, Typed and Secure Web Applications

How we build and rescue PHP applications today: strict types, disciplined Composer use, static analysis, performance work led by profiling, and security by default.

Rough blocks pass a set square, a lens and a padlock box and leave as neat, verified stacks, like a modern PHP pipeline.

Most teams that come to us for PHP development want one of two things: a new web application that will stay easy to change for years, or an existing one that has become slow, fragile or hard to staff. Both come down to the same question. Is the codebase written like modern PHP, or like the PHP that gave the language its old reputation?

Good looks like this: typed code that a static analyzer can reason about, dependencies pinned and audited through Composer, tests that run on every push, response times you have measured rather than guessed, and security handled by the framework and the pipeline instead of by memory. The language has changed a great deal. This is how we work with it.

What we build with PHP

PHP is at its best in request-and-response web software backed by a relational database, which describes a large share of real business applications. Typical projects:

  • Customer portals and self-service dashboards with role-based access
  • Back-office systems for operations teams: bookings, orders, approvals, inventory
  • JSON APIs that serve mobile apps and single-page front ends
  • Integrations that connect a product to payment providers, ERPs, CRMs and accounting tools
  • Custom modules for existing platforms, including e-commerce stores
  • Rescue and modernization of older PHP and MySQL applications that still run the business

For new products we build on a framework. Laravel is our default when delivery speed and a broad first-party toolkit matter; Symfony suits teams that prefer explicit configuration and reusable components. For existing systems we meet the code where it is, including long-lived CodeIgniter applications and framework-less code.

How modern PHP development looks in practice

Current PHP is a typed language if you let it be. We enable strict types in every file and use the features that make intent explicit: typed properties, union and nullable types, enums instead of magic strings, readonly properties for value objects, constructor promotion, and match expressions instead of long switch chains. The payoff is not style. Tools can catch mistakes before your users do.

Composer hygiene

  • The lock file is committed, so every environment installs exactly the same versions.
  • Version constraints follow semantic versioning, and upgrades happen in small, reviewed steps.
  • composer audit runs in CI and fails the build on known vulnerabilities.
  • Production installs skip development dependencies and use an optimized autoloader.
  • Abandoned packages are replaced before they become a security problem.

Static analysis and automated refactoring

PHPStan or Psalm runs on every pull request. On an existing codebase we start with a baseline that records today’s errors, block new ones immediately, and raise the strictness level over time. Rector handles the mechanical side of upgrades, such as adopting newer syntax or replacing deprecated calls, so reviewers can focus on behavior. A coding standard enforced by PHP-CS-Fixer or PHP_CodeSniffer ends style debates in review.

Architecture and stack choices

Most products start best as a well-structured monolith: one deployable application with clear internal modules, a relational database and a queue for slow work. We split out services when a boundary is proven and a team or scaling need justifies the extra operational work, not before.

  • Database. MySQL or MariaDB when your team and hosting already know them; PostgreSQL when you need richer data types, stricter constraints or more advanced queries. Either performs well with good indexes and migrations kept in version control.
  • Caching and queues. Redis covers cache, sessions, locks and queues for most applications. Email, PDF generation, imports and webhook calls move to background jobs.
  • Runtime. Nginx with PHP-FPM is the predictable default. Application servers such as FrankenPHP in worker mode, RoadRunner or Swoole keep the app booted between requests and can cut latency, but state shared across requests becomes your problem. We adopt them when profiling shows bootstrap cost matters.
  • Front end. Server-rendered templates for admin-heavy apps; an API with a JavaScript front end when the interface is highly interactive or shared with mobile.

Performance work that starts with a profiler

Slow PHP applications are rarely slow because of PHP. They are slow because of what the code asks the database and the network to do. We measure first, with Blackfire, Tideways, SPX or the Xdebug profiler locally and an APM in production, then fix what the data shows. The usual findings:

A flame graph with one wide amber hot spot under a magnifying lens, beside a row of identical repeated database calls.
  • N+1 queries hidden inside ORM relationships and templates
  • Missing indexes, and queries that load whole tables just to count rows
  • Third-party API calls made synchronously inside a page request
  • File-based sessions that lock, so parallel requests from one user wait in line
  • No cache for data that changes rarely but is read constantly

Server configuration matters too. OPcache should be on with enough memory, and in production it can skip file timestamp checks as long as each deploy reloads PHP-FPM. The number of FPM workers should be sized to available memory, not left at defaults. The JIT compiler helps CPU-heavy code, but typical web requests spend their time waiting on I/O, so it is rarely where the gains are.

Security that does not depend on memory

The vulnerabilities that hurt PHP applications are rarely exotic. They are old, well-understood mistakes, so the fix is to make the safe path the default one:

A request path through a maze where every wrong turn is walled off, passing a sieve, a sealed envelope and a lock.
  • Prepared statements or a query builder for every database call, never SQL built from strings
  • Context-aware output escaping, ideally through a template engine that escapes by default
  • CSRF tokens on every state-changing form, and authorization checked per record, not just per page
  • Passwords stored with password_hash(), with legacy MD5 or SHA-1 hashes upgraded at each user’s next login
  • Tokens generated with random_bytes(), never rand() or uniqid()
  • Session IDs regenerated at login, and cookies marked Secure, HttpOnly and SameSite
  • No unserialize() on anything a user can touch; JSON instead
  • Uploads validated by content, stored outside the web root and served through the application
  • Errors logged, never displayed; secrets kept in the environment, never in the repository

Just as important: run a PHP version that still receives security fixes. Every release line has a published support window, and once it closes, no amount of careful application code will patch the runtime underneath it.

When PHP is the right choice, and when it is not

PHP is a strong fit when your product is a web application or API with ordinary request patterns, when you want a mature ecosystem and a large hiring pool, and when hosting flexibility matters. Its shared-nothing model, where every request starts clean, is also forgiving: a leak or a corrupted state rarely outlives a single request.

It is the wrong default for a few workloads. Systems built around many long-lived connections, such as live collaboration or high-volume real-time feeds, are more natural in Node.js, Go or Elixir. Data science and machine learning belong in Python. And if your team already works in C# or TypeScript, moving to PHP rarely pays for itself. We say so during discovery, not after the build.

How we work, from first audit to launch

Every engagement starts with discovery. For a new product, our business analysts turn goals into user flows and acceptance criteria. For an existing application, we audit the code, dependencies and infrastructure, and you receive a written report that ranks risks by impact and effort.

  1. Design. Data model, module boundaries, API contracts and the screens that matter most.
  2. Build. Short iterations with a working demo at the end of each, and CI running tests, static analysis and dependency audits on every change.
  3. QA. Our testers write test plans from the acceptance criteria and maintain a regression suite that grows with the product.
  4. Launch. Automated, repeatable deploys, database migrations that are safe while the previous version is still serving traffic, and monitoring in place before the first user arrives.
  5. Iterate. Error tracking and performance data decide what we improve next.

With legacy code, we add characterization tests around the riskiest flows before changing anything, then upgrade PHP in steps and refactor behind those tests. A full rewrite is rarely the right first move.

Either way, the code lives in your repository, and you get documentation and regular written progress reports. The team is shaped to the work: a dedicated product team from idea to launch, or a focused engagement on a single application. Our backend development overview covers the server side in more depth.

Frequently asked questions

Is PHP still a good choice for a new project?

For most web applications and APIs, yes. Modern PHP is typed, fast enough for typical workloads, and backed by mature frameworks and tooling. Choose something else when the workload is dominated by long-lived connections or heavy computation.

Can you take over a PHP application another team built?

Yes, and it is a large part of our PHP work. We begin with an audit so you know what you have, then stabilize the riskiest areas before adding features.

Should we rewrite our old PHP application or upgrade it?

Usually upgrade. Incremental refactoring behind tests keeps the business running and delivers value along the way. A rewrite makes sense when the data model no longer fits the business or the code cannot be tested at all.

Do you only work with MySQL?

No. We work with MySQL, MariaDB and PostgreSQL, and we choose based on your data, your team and your hosting rather than habit.

How do you keep a PHP application secure after launch?

With automated dependency audits, scheduled PHP and framework upgrades, error monitoring, and periodic reviews of authentication and authorization code. Security is ongoing maintenance, not a milestone.

Whether you are starting a new PHP application or trying to make an old one dependable again, we would like to hear about it. Tell us about your project, and we will suggest a sensible first step.